テストコードをTSにするかJSにするかという話、とりあえずデフォルトのJSでやってたけどimmerで更新してCypressでテストで、型で補完が効かないせいで早速Typoしたので、やっぱりCypressのTypeScript化は必須だという結論になった。
TypeScript | Cypress Documentationを参考にTypeScript化する。
下記のようなことを書いてある記述を見かけたがこれはcypressディレクトリの中にtsconfigを置く場合は適切ではない、そうでない場合もカスタムコマンドのことを無視してる tsconfig.json
"include": [
"cypress/integration/*.ts",
"cypress/integration/**/*.ts",
]
相対パスなのでこんな感じ(full) tsconfig.json
{
"compilerOptions": {
"target": "es5",
"lib": [
"es5",
"dom"
],
"types": [
"cypress"
]
},
"include": [
"*.ts",
"**/*.ts",
"../src/*.ts",
"../src/**/*.ts",
]
}
*.tsxをインポートしようとすると—jsxが必要というエラーになるが、そもそも今回のユースケースでtsxをインポートできる必要があるか不明だったのでシンプルに保つことにした。
import { State } from "reactn/default";
して型宣言をすればちゃんとTypoが警告されるようになった
ところで@ts-ignore
してる件、
cy.window().its("movidea").then((movidea) => { ... }
だと引数はanyで、
cy.get("@movidea").then((movidea) => { ... }
だと JQuery<HTMLElement>
になる。
いちいちmovideaをキャストするのは不便。 カスタムコマンドを作るか
ここでサンプルの通りにしたつもりでType 'Chainable' is not generic.
とかProperty 'movidea' does not exist on type 'cy & EventEmitter'.
とかになったりすったもんだがあったが最終的にこれでOK
cypress/support/index.ts
/// <reference types="cypress" />
import { TMovidea } from "../../src/exposeGlobal";
declare global {
namespace Cypress {
interface Chainable {
movidea(callback: (movidea: TMovidea) => void): Chainable;
}
}
}
Cypress.Commands.add("movidea", (callback: (movidea: TMovidea) => void) => {
return cy.window().its("movidea").then(callback);
});
公式ドキュメントに下記のように書いてあったんだけど、これエラーにならない? ts
declare namespace Cypress {
interface Chainable {
/**
* Custom command to select DOM element by data-cy attribute.
* @example cy.dataCy('greeting')
*/
dataCy(value: string): Chainable<Element>
}
}
Cypressのソースを確認したら ts
declare global {
namespace Cypress {
// TODO: Why is Subject unused?
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chainable<Subject = any> {
...
ってなってるので、globalを補ったら期待通りに動くようになった。
最終的にテストコード中でこう書けるようになった。破壊的に更新してるように見えるけどimmerを使って非破壊的更新がされてて、ちゃんとReactのフックによる再描画が走る。 test.ts
cy.movidea((movidea) => {
movidea.updateGlobal((g) => {
g.itemStore["1"].position = [100, 0];
});
});