Skip to content

Commit 34c48b5

Browse files
committed
Setup Cypress and add some basic tests to start
Other Changes: - When game is over, prevent any more swipe actions until player starts new game
1 parent 27a796b commit 34c48b5

32 files changed

+1498
-2021
lines changed

.github/workflows/run-tests.yml

+14-14
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@ jobs:
1919
with:
2020
name: unit-test-results
2121
path: ./results/unit-test-results.xml
22-
# cypress-run:
23-
# runs-on: ubuntu-latest
24-
# steps:
25-
# - run: echo "Checking out ${{ github.ref }} from ${{ github.repository }}."
26-
# - name: Check out repository code
27-
# uses: actions/checkout@v4
28-
# - name: Run Cypress tests
29-
# uses: cypress-io/github-action@v6
30-
# - name: Upload test results
31-
# if: always()
32-
# uses: actions/upload-artifact@v4
33-
# with:
34-
# name: cypress-test-results
35-
# path: ./results/cypress-test-results-*.xml
22+
cypress-run:
23+
runs-on: ubuntu-latest
24+
steps:
25+
- run: echo "Checking out ${{ github.ref }} from ${{ github.repository }}."
26+
- name: Check out repository code
27+
uses: actions/checkout@v4
28+
- name: Run Cypress tests
29+
uses: cypress-io/github-action@v6
30+
- name: Upload test results
31+
if: always()
32+
uses: actions/upload-artifact@v4
33+
with:
34+
name: cypress-test-results
35+
path: ./results/cypress-test-results-*.xml
3636
publish-test-results:
3737
if: always()
3838
needs: [test-game-logic] #, cypress-run]

cypress.config.js cypress.config.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
const { defineConfig } = require("cypress");
1+
import { defineConfig } from "cypress";
22

3-
module.exports = defineConfig({
3+
export default defineConfig({
44
e2e: {
5+
baseUrl: "http://localhost:5173",
56
setupNodeEvents(on, config) {
67
// implement node event listeners here
78

cypress/e2e/game/dialog.cy.js cypress/e2e/game/dialog.cy.ts

+36-75
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
11
/// <reference types="cypress" />
22

3-
const DAY_MS = 86400000;
4-
// March 23 2022 - initial release date
5-
const FIRST_DAY_MS = 1647993600000;
3+
import { GamePersistentState } from "../../../src/game";
64

7-
describe("dialogs", () => {
5+
// TODO: Implement these tests
6+
describe.skip("dialogs", () => {
87
beforeEach(() => {
9-
// only mock the "Date" object, otherwise events that use setTimeout like dialog messages won't work
10-
// https://github.com/cypress-io/cypress/issues/7455#issuecomment-635278631
11-
cy.clock(FIRST_DAY_MS + DAY_MS * 1 + (DAY_MS * 1) / 2, ["Date"]);
12-
cy.intercept("/words.txt", {
13-
fixture: "words.txt",
14-
});
158
cy.clearBrowserCache();
169
cy.visit("/", {
1710
onBeforeLoad: () => {
18-
window.localStorage.setItem("played_before", true);
11+
const persistentState: GamePersistentState = {
12+
highscore: 0,
13+
unlockables: {},
14+
hasPlayedBefore: true,
15+
};
16+
window.localStorage.setItem("persistent-state", JSON.stringify(persistentState));
1917
},
2018
});
21-
cy.waitForGameReady();
2219

23-
// The How to Play dialog is an example of a closable dialog that can be triggered in normal usage
24-
cy.get(".help-link").click();
20+
// The Debug dialog is an example of a closable dialog that can be triggered in normal usage (during debug mode)
21+
cy.get("button#debug").click();
2522
});
2623

2724
describe("general dialog behaviour", () => {
@@ -30,53 +27,17 @@ describe("dialogs", () => {
3027
cy.get(".overlay-back").should("be.visible");
3128
});
3229

33-
[
34-
{
35-
name: "backspace",
36-
input: "backspace",
37-
},
38-
{
39-
name: "f key",
40-
input: "f",
41-
},
42-
{
43-
name: "enter key",
44-
input: "enter",
45-
},
46-
].forEach((def) => {
47-
it(`prevents inputs from being made on touch keyboard - case '${def.name}'`, (done) => {
48-
cy.keyboardItem(def.input).shouldNotBeActionable(done);
49-
});
50-
});
51-
5230
it("prevents player from making any more inputs with physical keyboard", () => {
53-
for (let i = 1; i <= 6; i++) {
54-
cy.inputRowShouldBeEmpty(i);
55-
}
56-
57-
cy.get("body").type("{backspace}");
58-
59-
for (let i = 1; i <= 6; i++) {
60-
cy.inputRowShouldBeEmpty(i);
61-
}
31+
// TODO: Verify the game board at this point
6232

63-
cy.get("body").type("f");
33+
cy.get("body").type("{rightArrow}");
34+
cy.get("body").type("{downArrow}");
35+
cy.get("body").type("{leftArrow}");
36+
cy.get("body").type("{upArrow}");
6437

65-
for (let i = 1; i <= 6; i++) {
66-
cy.inputRowShouldBeEmpty(i);
67-
}
38+
// TODO: Verify the game board did not change
6839

69-
cy.inputRow(1).should("have.id", "current-input");
70-
cy.inputRow(2).should("not.have.id", "current-input");
71-
72-
cy.get("body").type("{enter}");
73-
74-
for (let i = 1; i <= 6; i++) {
75-
cy.inputRowShouldBeEmpty(i);
76-
}
77-
78-
cy.inputRow(1).should("have.id", "current-input");
79-
cy.inputRow(2).should("not.have.id", "current-input");
40+
throw new Error("TODO: Verify the game board did not change after doing some inputs");
8041
});
8142

8243
// NTS: If dialog does not appear on the screen for some reason, which should never happen anyway under normal operation, then player can make physical key inputs.
@@ -98,32 +59,34 @@ describe("dialogs", () => {
9859
cy.get(".dialog").should("be.visible");
9960
cy.get(".overlay-back").should("be.visible");
10061

101-
cy.get("body").click({
102-
position: "left",
103-
});
62+
cy.get("body").click("left");
10463

10564
cy.get(".dialog").should("not.exist");
10665
cy.get(".overlay-back").should("not.be.visible");
10766
});
10867

10968
it("allows inputs to be made again after closing", () => {
110-
cy.get("body").type("b");
69+
// TODO: Verify the game board at this point
11170

112-
for (let i = 1; i <= 6; i++) {
113-
cy.inputRowShouldBeEmpty(i);
114-
}
71+
cy.get("body").type("{rightArrow}");
72+
cy.get("body").type("{downArrow}");
73+
cy.get("body").type("{leftArrow}");
74+
cy.get("body").type("{upArrow}");
75+
76+
// TODO: Verify the game board did not change
11577

11678
cy.get(".dialog > .close").click();
11779

118-
cy.get("body").type("b");
80+
// TODO: Verify the game board at this point
81+
82+
cy.get("body").type("{rightArrow}");
83+
cy.get("body").type("{downArrow}");
84+
cy.get("body").type("{leftArrow}");
85+
cy.get("body").type("{upArrow}");
11986

120-
cy.inputRow(1).inputCell(1).inputLetter().should("have.text", "b");
121-
for (let i = 2; i <= 5; i++) {
122-
cy.inputRow(1).inputCell(i).inputLetter().should("be.empty");
123-
}
124-
for (let i = 2; i <= 6; i++) {
125-
cy.inputRowShouldBeEmpty(i);
126-
}
87+
// TODO: Verify the game board did change
88+
89+
throw new Error("TODO: Verify the game board did change after closing");
12790
});
12891

12992
it("can be closed by pressing enter key", () => {
@@ -171,9 +134,7 @@ describe("dialogs", () => {
171134
it("can not be closed by clicking elsewhere besides the dialog", () => {
172135
cy.get(".dialog").should("be.visible");
173136

174-
cy.get("body").click({
175-
position: "left",
176-
});
137+
cy.get("body").click("left");
177138

178139
cy.get(".dialog").should("be.visible");
179140
});

cypress/e2e/game/gameplay.cy.js

-21
This file was deleted.

cypress/e2e/game/gameplay.cy.ts

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/// <reference types="cypress" />
2+
3+
import { GameState, GamePersistentState } from "../../../src/game";
4+
import { Preferences } from "../../../src/preferences";
5+
6+
describe("gameplay", () => {
7+
beforeEach(() => {
8+
cy.clearBrowserCache();
9+
cy.visit("/", {
10+
onBeforeLoad: () => {
11+
const gameState: GameState = {
12+
board: [
13+
[0, 0, 0, 0],
14+
[0, 2, 0, 0],
15+
[0, 0, 4, 0],
16+
[0, 0, 0, 0],
17+
],
18+
ended: false,
19+
won: false,
20+
score: 0,
21+
didUndo: false,
22+
};
23+
const persistentState: GamePersistentState = {
24+
highscore: 0,
25+
unlockables: {},
26+
hasPlayedBefore: true,
27+
};
28+
const preferences: Preferences = {
29+
theme: "dark",
30+
};
31+
window.localStorage.setItem("game-state", JSON.stringify(gameState));
32+
window.localStorage.setItem("persistent-state", JSON.stringify(persistentState));
33+
window.localStorage.setItem("preferences", JSON.stringify(preferences));
34+
},
35+
});
36+
});
37+
38+
// TODO: Implement this test
39+
it.skip("should allow player to swipe to move the blocks", () => {
40+
throw new Error("Test not implemented");
41+
});
42+
43+
it("should allow player to move blocks using right arrow key", () => {
44+
cy.verifyBoard([
45+
[0, 0, 0, 0],
46+
[0, 2, 0, 0],
47+
[0, 0, 4, 0],
48+
[0, 0, 0, 0],
49+
]);
50+
51+
cy.get("body").type("{rightArrow}");
52+
53+
cy.verifyBoard([
54+
[undefined, undefined, undefined, undefined],
55+
[undefined, undefined, undefined, 2],
56+
[undefined, undefined, undefined, 4],
57+
[undefined, undefined, undefined, undefined],
58+
]);
59+
});
60+
61+
it("should allow player to move blocks using left arrow key", () => {
62+
cy.verifyBoard([
63+
[0, 0, 0, 0],
64+
[0, 2, 0, 0],
65+
[0, 0, 4, 0],
66+
[0, 0, 0, 0],
67+
]);
68+
69+
cy.get("body").type("{leftArrow}");
70+
71+
cy.verifyBoard([
72+
[undefined, undefined, undefined, undefined],
73+
[2, undefined, undefined, undefined],
74+
[4, undefined, undefined, undefined],
75+
[undefined, undefined, undefined, undefined],
76+
]);
77+
});
78+
79+
it("should allow player to move blocks using down arrow key", () => {
80+
cy.verifyBoard([
81+
[0, 0, 0, 0],
82+
[0, 2, 0, 0],
83+
[0, 0, 4, 0],
84+
[0, 0, 0, 0],
85+
]);
86+
87+
cy.get("body").type("{downArrow}");
88+
89+
cy.verifyBoard([
90+
[undefined, undefined, undefined, undefined],
91+
[undefined, undefined, undefined, undefined],
92+
[undefined, undefined, undefined, undefined],
93+
[undefined, 2, 4, undefined],
94+
]);
95+
});
96+
97+
it("should allow player to move blocks using up arrow key", () => {
98+
cy.verifyBoard([
99+
[0, 0, 0, 0],
100+
[0, 2, 0, 0],
101+
[0, 0, 4, 0],
102+
[0, 0, 0, 0],
103+
]);
104+
105+
cy.get("body").type("{upArrow}");
106+
107+
cy.verifyBoard([
108+
[undefined, 2, 4, undefined],
109+
[undefined, undefined, undefined, undefined],
110+
[undefined, undefined, undefined, undefined],
111+
[undefined, undefined, undefined, undefined],
112+
]);
113+
});
114+
115+
// TODO: Implement this test
116+
it.skip("should allow player to click new game to restart the game", () => {
117+
throw new Error("Test not implemented");
118+
});
119+
});

0 commit comments

Comments
 (0)