Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FRS-5 Testing #5

Merged
merged 34 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2c6e8b7
Updated FRS with testing section
stuart-bradley Feb 19, 2024
a79b7b3
Basic Cypress configuration
stuart-bradley Feb 19, 2024
b02c669
Change cypress github action image
stuart-bradley Feb 19, 2024
5158aa5
Added component test setup
stuart-bradley Feb 19, 2024
327fc7e
Added basic E2E tests
stuart-bradley Feb 19, 2024
2dac5c6
Finished E2E tests
stuart-bradley Feb 19, 2024
5765a24
Fixed missing config in action
stuart-bradley Feb 19, 2024
4f3d868
Add wait to test
stuart-bradley Feb 19, 2024
aa3ef7d
Try index select
stuart-bradley Feb 19, 2024
4292f61
Add focus
stuart-bradley Feb 19, 2024
da9f6f5
Add logging
stuart-bradley Feb 19, 2024
0011499
Include debug logs
stuart-bradley Feb 19, 2024
d28bf49
Include debug logs
stuart-bradley Feb 19, 2024
d084e68
Update github action
stuart-bradley Feb 19, 2024
b820531
Fix action
stuart-bradley Feb 19, 2024
9afdbcc
different assertion
stuart-bradley Feb 19, 2024
2ec39dd
New github action
stuart-bradley Feb 19, 2024
f6b24eb
New github action
stuart-bradley Feb 19, 2024
1a96b3e
Remove wait-on
stuart-bradley Feb 19, 2024
f94cf0e
Following nextjs guide for starting server
stuart-bradley Feb 19, 2024
9762608
Move start-server and test to dev deps
stuart-bradley Feb 19, 2024
47e37ff
Added caching
stuart-bradley Feb 19, 2024
931fd6f
Break tests to check artifacts
stuart-bradley Feb 19, 2024
035d56b
Final Github actions
stuart-bradley Feb 19, 2024
4220ccf
Completed BoardFrom component tests
stuart-bradley Feb 19, 2024
534056b
Remove debug mode from E2E github action
stuart-bradley Feb 19, 2024
b33d560
Added test for BoardGrid component
stuart-bradley Feb 20, 2024
e3892bc
Updated FRS
stuart-bradley Feb 20, 2024
2e4a271
Added hardcoded functionality for Layout props.
stuart-bradley Feb 20, 2024
f4e8619
Tided up TS
stuart-bradley Feb 20, 2024
218b352
Added basic getLayoutProps test
stuart-bradley Feb 20, 2024
b5f3248
Set layout constants
stuart-bradley Feb 21, 2024
cc77af2
Updated FRS
stuart-bradley Feb 21, 2024
6a55ae5
Added Github issue links
stuart-bradley Feb 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/e2e_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: End-to-end tests
on:
push:
branches:
- main

jobs:
cypress-run:
runs-on: ubuntu-latest
name: Run Cypress E2E tests
steps:
- name: Check out Git repository
uses: actions/checkout@v4

- name: Cache
uses: actions/cache@v3
with:
path: |
~/.npm
${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: "npm"

- name: Install Node.js dependencies
run: npm ci

- name: Build
run: npm run build --if-present

- name: Run Cypress Tests
run: npm run cypress:ci

- name: Upload Photo Artifacts
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-screenshots
path: cypress/screenshots
if-no-files-found: ignore

- name: Upload Video Artifacts
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-videos
path: cypress/videos
if-no-files-found: ignore
20 changes: 15 additions & 5 deletions .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copied from https://github.com/marketplace/actions/lint-action
# And: https://nextjs.org/docs/pages/building-your-application/deploying/ci-build-caching#github-actions

name: Lint and Test

Expand All @@ -17,25 +18,34 @@ jobs:

steps:
- name: Check out Git repository
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Cache
uses: actions/cache@v3
with:
path: |
~/.npm
${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: "npm"

- name: Install Node.js dependencies
run: npm ci

- name: Build
run: npm run build --if-present

- name: Lint
uses: wearerequired/lint-action@v2
with:
eslint: true
prettier: true

- name: Build
run: npm run build --if-present

- name: Test
run: npm test
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ Full documentation can be found in the [documentation](documentation) folder.

## Dependencies

- [Next.js](https://nextjs.org/) `14.1.0`
- [Next.js](https://nextjs.org/) `14.1.*`
- [React](https://react.dev/) `18.*`
- [react-hexgrid](https://github.com/Hellenic/react-hexgrid) `2.0.0@beta`
- [emotion](https://emotion.sh/docs/introduction) `11.11.3` (dependency not imported by react-hexgrid)
- [Zod](https://zod.dev/) `3.22.4`
- [emotion](https://emotion.sh/docs/introduction) `11.11.*` (dependency not imported by react-hexgrid)
- [Zod](https://zod.dev/) `3.22.*`

### Dev Dependencies

- [Typescript](https://www.typescriptlang.org/) `v5.*`
- [Tailwind CSS](https://tailwindcss.com/) `v3.3.*`
- [ESLint](https://eslint.org/) `8.56.0`
- [Prettier](https://prettier.io/) `3.2.5`
- [pre-commit](https://pre-commit.com/) `3.5.0`
- [vitest](https://vitest.dev/) `1.2.2`
- [ESLint](https://eslint.org/) `8.56.*`
- [Prettier](https://prettier.io/) `3.2.*`
- [pre-commit](https://pre-commit.com/) `3.5.*`
- [vitest](https://vitest.dev/) `1.2.*`
- [Cypress](https://www.cypress.io/) `13.6.*`
- [start-server-and-test](https://github.com/bahmutov/start-server-and-test) `2.0.3`
- [testing-library/react](https://testing-library.com/docs/react-testing-library/intro) `14.2.*`
- [testing-library/user-event](https://testing-library.com/docs/user-event/intro) `14.5.*`
16 changes: 16 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineConfig } from "cypress";

export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},

component: {
devServer: {
framework: "next",
bundler: "webpack",
},
},
});
31 changes: 31 additions & 0 deletions cypress/e2e/app.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ALGORITHM_COASTAL, ALGORITHM_RANDOM } from "../../src/lib/constants";

describe("BoardForm", () => {
it("should display a random board on submit", () => {
cy.visit("http://localhost:3000/");

// Assert form is in base state.
cy.get('[data-testid="use-seafarers-checkbox"]').should("not.be.checked");
cy.get('[data-testid="rand-algorithm-selector"] option:selected').should(
"have.value",
ALGORITHM_RANDOM,
);
cy.get('[data-testid="rand-algorithm-selector"] option').should(
"not.have.value",
ALGORITHM_COASTAL,
);

// Select the seafarers checkbox. force: true is required due to div overlaying input.
cy.get('[data-testid="use-seafarers-checkbox"]').check({ force: true });

// Assert it's possible to select a seafarers algorithm.
cy.get('[data-testid="rand-algorithm-selector"]').select(ALGORITHM_COASTAL);

cy.get('[data-testid="submit-button"]').click();
// Top level node of an SVG is a single <g>, so to check hexagons we have to go a level lower.
cy.get('[data-testid="hexgrid-svg"]')
.children()
.first()
.should("have.descendants", "g.hexagon-group");
});
});
5 changes: 5 additions & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "[email protected]",
"body": "Fixtures are a great way to mock data for responses to routes"
}
37 changes: 37 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// <reference types="cypress" />
// ***********************************************
// This example commands.ts shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
//
// declare global {
// namespace Cypress {
// interface Chainable {
// login(email: string, password: string): Chainable<void>
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
14 changes: 14 additions & 0 deletions cypress/support/component-index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Components App</title>
<!-- Used by Next.js to inject CSS. -->
<div id="__next_css__DO_NOT_USE__"></div>
</head>
<body>
<div data-cy-root></div>
</body>
</html>
39 changes: 39 additions & 0 deletions cypress/support/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// ***********************************************************
// This example support/component.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import "./commands";

// Alternatively you can use CommonJS syntax:
// require('./commands')

import { mount } from "cypress/react18";

// Augment the Cypress namespace to include type definitions for
// your custom command.
// Alternatively, can be defined in cypress/support/component.d.ts
// with a <reference path="./component" /> at the top of your spec.
declare global {
namespace Cypress {
interface Chainable {
mount: typeof mount;
}
}
}

Cypress.Commands.add("mount", mount);

// Example use:
// cy.mount(<MyComponent />)
20 changes: 20 additions & 0 deletions cypress/support/e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import "./commands";

// Alternatively you can use CommonJS syntax:
// require('./commands')
52 changes: 52 additions & 0 deletions documentation/functional_requirements_specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,44 @@ functionality.

### 5 Testing

Next.js has a number of guides for setting up various
[testing libraries](https://nextjs.org/docs/app/building-your-application/testing) with the framework.

While using [Jest](https://jestjs.io/) was attempted (due to prior knowledge), initial configuration for Typescript didn't work so
[Vitest](https://vitest.dev/) should be used for unit testing.

For E2E testing, [Cypress](https://www.cypress.io/) due to prior experience. As it stands Cypress does not support component testing with
[Server Actions](https://nextjs.org/docs/app/building-your-application/testing/cypress), therefore it's best to stick
with E2E testing. Component testing can be handled inside Vitest.

See Appendix D for a list of errors found during the testing process.

### 5.1 Unit Testing - Vitest

The main file that should be unit tested is `src/lib/CatanBoardGenerator.ts`, as this file generates the all the
possible Catan boards. A test suite should be setup with parameterised tests for all the different algorithms.

Additionally, `src/lib/utils.ts` should be tested to confirm the functions work as expected.

### 5.2 Component Testing - Vitest

`<BoardFrom />` should be tested in the following ways:

1. Assert the form renders with the expected fields.
2. Assert the form select options change when `Use Seafarers` is clicked.

`<BoardGrid />` should be tested in the following ways:

1. Mock `useParams` and assert an `svg` is created.

### 5.3 E2E Testing - Cypress

E2E should cover as many user paths as possible, including those covered in 5.1 and 5.2 for completeness. Given there is
a single user path in the application:

1. Configure and submit a form, asserting a `svg` is created. This test will implicitly cover much of the functionality
of 5.2.

### 6 Containerisation

#### 6.1 Docker
Expand Down Expand Up @@ -204,3 +242,17 @@ Taken from this [document](https://idoc.pub/documents/catan-components-list-wl1p
- Desert: 1
- Gold: 2
- Ocean: 7

### D: Errors from Testing

1. The [Cypress Github Action](https://github.com/cypress-io/github-action) caused a failure on the
`should change select values when use-seafarers is checked` test, as it could not find the new options in the select.
The test works locally, and fine when a manual github action is setup.
2. [#6](https://github.com/stuart-bradley/catan-randomiser-js/issues/6): `TypeError: useFormStatus is not a function` when Component testing `<BoardForm />`. This appears to be a Typescript
issue, but the functionality is not required for MVP so has been removed.
3. Different sizes of board change the SVG viewport, moving and scaling the SVG differently. Functionality should be
added to change teh `<Layout />` component `size` and `origin` props based on the incoming board.
4. [#7](https://github.com/stuart-bradley/catan-randomiser-js/issues/7) The Next.js [App Router](https://nextjs.org/docs/app) does not have functionality for
[shallow routing](https://nextjs.org/docs/pages/building-your-application/routing/linking-and-navigating#shallow-routing)
(which the Page Router does). This means it's not possible to avoid a redirect to update the URL and form state is lost.
Again, this is not MVP functionality so can be ignored for now.
Loading
Loading