Skip to content

Commit

Permalink
Merge pull request #1 from brocoders/feat/e2e-test
Browse files Browse the repository at this point in the history
tests: add Cypress
  • Loading branch information
Shchepotin authored Sep 18, 2023
2 parents b3b2852 + 2494a21 commit cad68d3
Show file tree
Hide file tree
Showing 18 changed files with 1,772 additions and 33 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"root": true,
"rules": {
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-namespace": "off",
"no-restricted-syntax": [
"error",
{
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: E2E Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
cypress-run:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
- name: Cypress run
uses: cypress-io/github-action@v6
with:
build: cp example.env.local .env.local
start: npm run dev
- name: Artifacts
uses: actions/upload-artifact@v3
if: failure()
with:
name: cypress-screenshots
path: cypress/screenshots
if-no-files-found: ignore # 'warn' or 'error' are also available, defaults to `warn`
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ReactJS boilerplate (WIP 🚧)
# ReactJS Boilerplate (WIP 🚧)

## Getting Started

Expand All @@ -9,3 +9,17 @@ cp example.env.local .env.local

npm run dev
```

## Features

- [x] Next.js
- [x] TypeScript
- [x] [i18n](https://react.i18next.com/) (based on https://github.com/i18next/next-13-app-dir-i18next-example)
- [x] [Material UI](https://mui.com/)
- [x] [React Hook Form](https://react-hook-form.com/)
- [ ] React Query
- [x] Auth (Sign in, Sign up, Reset password, Confirm email, Refresh Token)
- [x] File upload
- [x] E2E tests (Cypress)
- [x] ESLint
- [x] CI (GitHub Actions)
13 changes: 13 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineConfig } from "cypress";

export default defineConfig({
e2e: {
setupNodeEvents() {
// implement node event listeners here
},
// Need for waiting api server
defaultCommandTimeout: 60000,
viewportWidth: 1200,
baseUrl: "http://localhost:3000",
},
});
40 changes: 40 additions & 0 deletions cypress/e2e/1-auth/sign-in.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/// <reference types="cypress" />

import { customAlphabet } from "nanoid";
const nanoid = customAlphabet("0123456789qwertyuiopasdfghjklzxcvbnm", 10);

describe("Sign In", () => {
let email: string;
let password: string;

beforeEach(() => {
email = `test${nanoid()}@example.com`;
password = nanoid();

cy.createNewUser({
email,
password,
firstName: `FirstName${nanoid()}`,
lastName: `LastName${nanoid()}`,
});
cy.get('[data-testid="profile-menu-item"]').click();
cy.get('[data-testid="logout-menu-item"]').click();

cy.visit("/sign-in");
});

it("Successful Sign In", () => {
cy.get('[data-testid="email"]').type(email);
cy.get('[data-testid="password"]').type(password);
cy.get('[data-testid="sign-in-submit"]').click();
cy.location("pathname").should("not.include", "/sign-in");
});

it("Successful Sign In with redirect", () => {
cy.visit("/profile");
cy.get('[data-testid="email"]').type(email);
cy.get('[data-testid="password"]').type(password);
cy.get('[data-testid="sign-in-submit"]').click();
cy.location("pathname").should("include", "/profile");
});
});
37 changes: 37 additions & 0 deletions cypress/e2e/1-auth/sign-up.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// <reference types="cypress" />

import { customAlphabet } from "nanoid";
const nanoid = customAlphabet("0123456789qwertyuiopasdfghjklzxcvbnm", 10);

describe("Sign Up", () => {
beforeEach(() => {
cy.visit("/sign-up");
});

it("Successful Sign Up", () => {
cy.get('[data-testid="firstName"]').type(`FirstName${nanoid()}`);
cy.get('[data-testid="lastName"]').type(`LastName${nanoid()}`);
cy.get('[data-testid="email"]').type(`test${nanoid()}@example.com`);
cy.get('[data-testid="password"]').type(nanoid());
cy.get('[data-testid="sign-up-submit"]').click();
cy.location("pathname").should("not.include", "/sign-up");
});

it("Fail on Sign Up with existing email", () => {
const email = `test${nanoid()}@example.com`;
cy.get('[data-testid="firstName"]').type(`FirstName${nanoid()}`);
cy.get('[data-testid="lastName"]').type(`LastName${nanoid()}`);
cy.get('[data-testid="email"]').type(email);
cy.get('[data-testid="password"]').type(nanoid());
cy.get('[data-testid="sign-up-submit"]').click();
cy.get('[data-testid="profile-menu-item"]').click();
cy.get('[data-testid="logout-menu-item"]').click();
cy.visit("/sign-up");
cy.get('[data-testid="firstName"]').type(`FirstName${nanoid()}`);
cy.get('[data-testid="lastName"]').type(`LastName${nanoid()}`);
cy.get('[data-testid="email"]').type(email);
cy.get('[data-testid="password"]').type(nanoid());
cy.get('[data-testid="sign-up-submit"]').click();
cy.get('[data-testid="email-error"]').should("be.visible");
});
});
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
// ***********************************************

Cypress.Commands.add(
"createNewUser",
({ firstName, lastName, email, password }) => {
cy.visit("/sign-up");
cy.get('[data-testid="firstName"]').type(firstName);
cy.get('[data-testid="lastName"]').type(lastName);
cy.get('[data-testid="email"]').type(email);
cy.get('[data-testid="password"]').type(password);
cy.get('[data-testid="sign-up-submit"]').click();
}
);

export {};

declare global {
namespace Cypress {
interface Chainable {
createNewUser(params: {
email: string;
password: string;
firstName: string;
lastName: string;
}): Chainable<void>;
}
}
}
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')
Loading

0 comments on commit cad68d3

Please sign in to comment.