2021-07-14Movidea開発日記
今日の一枚
https://gyazo.com/e1f53457d5b6464ee09d9353282f24e7
Cypress、containsはDOMが選択されるが型がundefined
code:ts
cy.get("divdata-testid='2'").should((x) => {}); // x is JQuery<HTMLElement> cy.contains("A B").should((x) => {}); // x is undefined
これはDOMを取得する方法としての実装とアサーションとしての実装の両方があるせい。
こんな感じになってるが、cyがChainable<undefined>だからSubject=undefinedになってしまう。設計が悪い、名前を分けるべき。
code:cypress.d.ts
contains(content: string | number | RegExp, options?: Partial<Loggable & Timeoutable & CaseMatchable & Shadow>): Chainable<Subject>
contains<E extends Node = HTMLElement>(content: string | number | RegExp): Chainable<JQuery<E>>
...
interface cy extends Chainable<undefined> {}
それはさておき自分の実装としてはdata-testidを付けてあるので、それを使って選択するのをカスタムコマンドにしてやりやすくしようと考えた。
code:support/index.ts
declare global {
namespace Cypress {
interface Chainable {
...
testid(testid: string): Chainable<Element>;
hasPosition(x: number, y: number): Chainable<Element>;
}
}
}
Cypress.Commands.add("testid", (testid: string) => {
return cy.get(*[data-testid='${testid}']);
});
Cypress.Commands.add(
"hasPosition",
{
prevSubject: true,
},
(subject: Cypress.Chainable<Element>, x: number, y: number) => {
const cr = subject0.getBoundingClientRect(); expect(cr.x).equal(x);
expect(cr.y).equal(y);
return subject;
}
);
これで
cy.testid("1").hasPosition(159, 174);
と書けるようになった。
しかしこれはリトライが行われない。
code:support/index.ts
chai.use((_chai, utils) => {
function hasPosition(options) {
const cr = this._obj0.getBoundingClientRect(); this.assert(
cr.x === x,
expected x:${cr.x} is ${x},
expected x:${cr.x} is not ${x},
cr.x
);
this.assert(
cr.y === y,
expected y:${cr.y} is ${y},
expected y:${cr.y} is not ${y},
cr.y
);
}
_chai.Assertion.addMethod("hasPosition", hasPosition);
});
これで
cy.testid("1").should("hasPosition", [159, 174]);
と書けるようになった。
shouldだったらhaveだなと思うがそういうことを言い出すとそもそもChai的には
cy.testid("1").has.position([159, 174]);
と書けるべきなのでは、みたいな気持ちになってきて、これはCypressとChaiの境目あたりにあって話がややこしいので保留した。
下記のテストが簡潔に書けるようになった
code:test.ts
// before
expect(x0.getBoundingClientRect().x).equal(x1); expect(x0.getBoundingClientRect().y).equal(y1); });
// after
cy.testid("1").should("hasPosition", x1, y1); だいぶカスタムコマンドに慣れてきて、そもそもupdateGlobalもよく使うからカスタムコマンドにしたらいいなと気づいた
code:support/index.ts
Cypress.Commands.add("updateGlobal", (callback: (g: State) => void) => {
return cy.movidea((movidea) => {
movidea.updateGlobal(callback);
});
});
下記のようにいちいちmovideaを介さなくても状態更新ができるようになった
code:test.ts
// before
cy.movidea((movidea) => {
movidea.updateGlobal((g) => {
});
});
// after
cy.updateGlobal((g) => {
});
「アイテム3番(付箋B)を動かしたらアイテム1番(グループ)の位置はどこどこになるべき」というテスト。(アイテムIDもわかりやすい名前にした方がよかったな)
code:test.ts
cy.updateGlobal((g) => {
});
cy.testid("1").should("hasPosition", 55, 170); https://gyazo.com/4dbdecd6194f095b8cb9127af8d6fb9a
で、この状態からグループを閉じると場所がずれる。次はこれを直していこう。
code:test.ts
cy.updateGlobal((g) => {
(g.itemStore"1" as GroupItem).isOpen = false; });
https://gyazo.com/1d073cc26748ada8d0a52dd54919dad8
Cypress、テストの各段階のスナップショットが見れるので「微妙に4ピクセルずれるバグ」を確認することができた、便利
https://gyazo.com/085db82b0e553d535a2d7c4cc66c69ae
ここいらでもう一度RegroupからエクスポートされたJSONを表示してみよう。なるほどここまでちゃんとなると何がバグの原因かわかりやすい、グループの中のグループのバウンディングボックスが平行移動の情報を失ってるのが原因だな。
https://gyazo.com/9283591c224d11aa269132886d2a7230
直した。色々なところに波及するが、テストケースがあるので動作確認しやすくて良い。ちゃんとした見栄えになった。
https://gyazo.com/e1f53457d5b6464ee09d9353282f24e7
https://gyazo.com/0d1187d7fe01b6a4de30333c80c1948e
ほぼ同じ!
今までのテストケースも全部成功する。
明日はメニューやダイアログ周りをやる
OOUIの解説を読み直してたんだけど「新規作成」も「インポート」もタスク指向なんだよなぁ
オブジェクト指向UIにするとしたらどうなるのだろう
既存のマップを開くURLではないものにアクセスする時点で「新規作成」なのは当たり前だし、新規作成した後コンテンツを入れないということも考えにくいのだからそもそも最初からインポートウィザードが開いているべきなのかな
インポートではなく「付箋の追加」ではないか
URLからインポートするときのUIは?