NISHIO Hirokazu[Translate]
CypressのTypeScript化
テストコードをTSにするかJSにするかという話、とりあえずデフォルトのJSでやってたけどimmerで更新してCypressでテストで、型で補完が効かないせいで早速Typoしたので、やっぱりCypressTypeScript化は必須だという結論になった。


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]; }); });

"Engineer's way of creating knowledge" the English version of my book is now available on [Engineer's way of creating knowledge]

(C)NISHIO Hirokazu / Converted from [Scrapbox] at [Edit]