mirror of
https://github.com/Mastermindzh/react-starter-kit.git
synced 2025-01-20 10:31:00 +01:00
added cypress
This commit is contained in:
parent
3cb1759648
commit
30f27d26e6
@ -5,7 +5,13 @@
|
||||
"es6": true
|
||||
},
|
||||
"plugins": ["import"],
|
||||
"extends": ["eslint:recommended", "prettier", "react-app", "react-app/jest"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"prettier",
|
||||
"react-app",
|
||||
"react-app/jest",
|
||||
"plugin:cypress/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module",
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -66,3 +66,5 @@ bundle.zip
|
||||
#SonarCloud
|
||||
.scannerwork
|
||||
.angular/cache/
|
||||
|
||||
cypress/videos
|
||||
|
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -8,6 +8,7 @@
|
||||
"reduxjs",
|
||||
"SVGR",
|
||||
"tailwindcss",
|
||||
"testid",
|
||||
"typeahead",
|
||||
"uncompiled"
|
||||
],
|
||||
|
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.2.0] - 2022-06-27
|
||||
|
||||
- Added [cypress.io](https://www.cypress.io/)
|
||||
|
||||
## [0.1.0] - 2022-06-27
|
||||
|
||||
- Updated to React 18
|
||||
|
@ -31,6 +31,7 @@ Only the important files are shown
|
||||
.
|
||||
├── .vscode # vscode setup (debug, snippets, etc)
|
||||
├── config # tool configuration
|
||||
├── cypress # e2e tests
|
||||
├── dist # production version
|
||||
├── public # directory with public files (config, icons, etc)
|
||||
├── scripts # Modified default create-react-app scripts
|
||||
|
10
cypress.config.ts
Normal file
10
cypress.config.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { defineConfig } from "cypress";
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
video: false,
|
||||
});
|
14
cypress/e2e/navigation.cy.js
Normal file
14
cypress/e2e/navigation.cy.js
Normal file
@ -0,0 +1,14 @@
|
||||
describe("Application navigation", () => {
|
||||
beforeEach(() => {
|
||||
cy.visit("http://localhost:3000");
|
||||
});
|
||||
|
||||
it("Should render the navigation links", () => {
|
||||
cy.get("[data-testid='nav']");
|
||||
});
|
||||
|
||||
it("Should navigate to about when clicking on About", () => {
|
||||
cy.get('[data-testid="nav.about"]').click();
|
||||
cy.contains("about");
|
||||
});
|
||||
});
|
143
cypress/e2e/todo.example.cy.js
Normal file
143
cypress/e2e/todo.example.cy.js
Normal file
@ -0,0 +1,143 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
// Welcome to Cypress!
|
||||
//
|
||||
// This spec file contains a variety of sample tests
|
||||
// for a todo list app that are designed to demonstrate
|
||||
// the power of writing tests in Cypress.
|
||||
//
|
||||
// To learn more about how Cypress works and
|
||||
// what makes it such an awesome testing tool,
|
||||
// please read our getting started guide:
|
||||
// https://on.cypress.io/introduction-to-cypress
|
||||
|
||||
describe('example to-do app', () => {
|
||||
beforeEach(() => {
|
||||
// Cypress starts out with a blank slate for each test
|
||||
// so we must tell it to visit our website with the `cy.visit()` command.
|
||||
// Since we want to visit the same URL at the start of all our tests,
|
||||
// we include it in our beforeEach function so that it runs before each test
|
||||
cy.visit('https://example.cypress.io/todo')
|
||||
})
|
||||
|
||||
it('displays two todo items by default', () => {
|
||||
// We use the `cy.get()` command to get all elements that match the selector.
|
||||
// Then, we use `should` to assert that there are two matched items,
|
||||
// which are the two default items.
|
||||
cy.get('.todo-list li').should('have.length', 2)
|
||||
|
||||
// We can go even further and check that the default todos each contain
|
||||
// the correct text. We use the `first` and `last` functions
|
||||
// to get just the first and last matched elements individually,
|
||||
// and then perform an assertion with `should`.
|
||||
cy.get('.todo-list li').first().should('have.text', 'Pay electric bill')
|
||||
cy.get('.todo-list li').last().should('have.text', 'Walk the dog')
|
||||
})
|
||||
|
||||
it('can add new todo items', () => {
|
||||
// We'll store our item text in a variable so we can reuse it
|
||||
const newItem = 'Feed the cat'
|
||||
|
||||
// Let's get the input element and use the `type` command to
|
||||
// input our new list item. After typing the content of our item,
|
||||
// we need to type the enter key as well in order to submit the input.
|
||||
// This input has a data-test attribute so we'll use that to select the
|
||||
// element in accordance with best practices:
|
||||
// https://on.cypress.io/selecting-elements
|
||||
cy.get('[data-test=new-todo]').type(`${newItem}{enter}`)
|
||||
|
||||
// Now that we've typed our new item, let's check that it actually was added to the list.
|
||||
// Since it's the newest item, it should exist as the last element in the list.
|
||||
// In addition, with the two default items, we should have a total of 3 elements in the list.
|
||||
// Since assertions yield the element that was asserted on,
|
||||
// we can chain both of these assertions together into a single statement.
|
||||
cy.get('.todo-list li')
|
||||
.should('have.length', 3)
|
||||
.last()
|
||||
.should('have.text', newItem)
|
||||
})
|
||||
|
||||
it('can check off an item as completed', () => {
|
||||
// In addition to using the `get` command to get an element by selector,
|
||||
// we can also use the `contains` command to get an element by its contents.
|
||||
// However, this will yield the <label>, which is lowest-level element that contains the text.
|
||||
// In order to check the item, we'll find the <input> element for this <label>
|
||||
// by traversing up the dom to the parent element. From there, we can `find`
|
||||
// the child checkbox <input> element and use the `check` command to check it.
|
||||
cy.contains('Pay electric bill')
|
||||
.parent()
|
||||
.find('input[type=checkbox]')
|
||||
.check()
|
||||
|
||||
// Now that we've checked the button, we can go ahead and make sure
|
||||
// that the list element is now marked as completed.
|
||||
// Again we'll use `contains` to find the <label> element and then use the `parents` command
|
||||
// to traverse multiple levels up the dom until we find the corresponding <li> element.
|
||||
// Once we get that element, we can assert that it has the completed class.
|
||||
cy.contains('Pay electric bill')
|
||||
.parents('li')
|
||||
.should('have.class', 'completed')
|
||||
})
|
||||
|
||||
context('with a checked task', () => {
|
||||
beforeEach(() => {
|
||||
// We'll take the command we used above to check off an element
|
||||
// Since we want to perform multiple tests that start with checking
|
||||
// one element, we put it in the beforeEach hook
|
||||
// so that it runs at the start of every test.
|
||||
cy.contains('Pay electric bill')
|
||||
.parent()
|
||||
.find('input[type=checkbox]')
|
||||
.check()
|
||||
})
|
||||
|
||||
it('can filter for uncompleted tasks', () => {
|
||||
// We'll click on the "active" button in order to
|
||||
// display only incomplete items
|
||||
cy.contains('Active').click()
|
||||
|
||||
// After filtering, we can assert that there is only the one
|
||||
// incomplete item in the list.
|
||||
cy.get('.todo-list li')
|
||||
.should('have.length', 1)
|
||||
.first()
|
||||
.should('have.text', 'Walk the dog')
|
||||
|
||||
// For good measure, let's also assert that the task we checked off
|
||||
// does not exist on the page.
|
||||
cy.contains('Pay electric bill').should('not.exist')
|
||||
})
|
||||
|
||||
it('can filter for completed tasks', () => {
|
||||
// We can perform similar steps as the test above to ensure
|
||||
// that only completed tasks are shown
|
||||
cy.contains('Completed').click()
|
||||
|
||||
cy.get('.todo-list li')
|
||||
.should('have.length', 1)
|
||||
.first()
|
||||
.should('have.text', 'Pay electric bill')
|
||||
|
||||
cy.contains('Walk the dog').should('not.exist')
|
||||
})
|
||||
|
||||
it('can delete all completed tasks', () => {
|
||||
// First, let's click the "Clear completed" button
|
||||
// `contains` is actually serving two purposes here.
|
||||
// First, it's ensuring that the button exists within the dom.
|
||||
// This button only appears when at least one task is checked
|
||||
// so this command is implicitly verifying that it does exist.
|
||||
// Second, it selects the button so we can click it.
|
||||
cy.contains('Clear completed').click()
|
||||
|
||||
// Then we can make sure that there is only one element
|
||||
// in the list and our element does not exist
|
||||
cy.get('.todo-list li')
|
||||
.should('have.length', 1)
|
||||
.should('not.have.text', 'Pay electric bill')
|
||||
|
||||
// Finally, make sure that the clear button no longer exists.
|
||||
cy.contains('Clear completed').should('not.exist')
|
||||
})
|
||||
})
|
||||
})
|
5
cypress/fixtures/example.json
Normal file
5
cypress/fixtures/example.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "Some name",
|
||||
"email": "info@someName.com",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
37
cypress/support/commands.ts
Normal file
37
cypress/support/commands.ts
Normal file
@ -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>
|
||||
// }
|
||||
// }
|
||||
// }
|
20
cypress/support/e2e.ts
Normal file
20
cypress/support/e2e.ts
Normal file
@ -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')
|
2076
package-lock.json
generated
2076
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-starter-kit",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"description": "A modern, create-react-app-based, starter kit for React projects",
|
||||
"keywords": [
|
||||
"react",
|
||||
@ -27,14 +27,17 @@
|
||||
"build": "node scripts/build.js",
|
||||
"lint": "eslint src/**",
|
||||
"organize-package-json": "npx format-package -w && npx sort-package-json",
|
||||
"e2e": "cypress open -d --e2e",
|
||||
"e2e-ci": "cypress run",
|
||||
"start": "node scripts/start.js",
|
||||
"test": "node scripts/test.js",
|
||||
"test-ci": "node scripts/test.js --ci",
|
||||
"test-live-coverage": " concurrently --kill-others \"npm run test-with-coverage\" \"npx http-server -c-1 coverage/lcov-report\"",
|
||||
"test-with-coverage": "node scripts/test.js --coverage"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "npm run lint && lint-staged"
|
||||
"pre-commit": "npm run lint && lint-staged && npm run test-ci && npm run e2e-ci"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
@ -73,11 +76,13 @@
|
||||
"concurrently": "^7.2.2",
|
||||
"css-loader": "^6.5.1",
|
||||
"css-minimizer-webpack-plugin": "^3.2.0",
|
||||
"cypress": "^10.2.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"dotenv-expand": "^5.1.0",
|
||||
"eslint": "^8.3.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint-watch": "^8.0.0",
|
||||
|
@ -2,8 +2,11 @@ const config = {
|
||||
version: "0.1.0",
|
||||
};
|
||||
|
||||
window.config = config;
|
||||
|
||||
if (module) {
|
||||
try {
|
||||
window.config = config;
|
||||
if (module) {
|
||||
module.exports = config;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
@ -38,7 +38,12 @@ function isInMercurialRepository() {
|
||||
}
|
||||
|
||||
// Watch unless on CI or explicitly running all tests
|
||||
if (!process.env.CI && argv.indexOf("--watchAll") === -1 && argv.indexOf("--watchAll=false") === -1) {
|
||||
if (
|
||||
!process.env.CI &&
|
||||
!argv.indexOf("--ci" !== -1) &&
|
||||
argv.indexOf("--watchAll") === -1 &&
|
||||
argv.indexOf("--watchAll=false") === -1
|
||||
) {
|
||||
// https://github.com/facebook/create-react-app/issues/5210
|
||||
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
|
||||
argv.push(hasSourceControl ? "--watch" : "--watchAll");
|
||||
|
@ -10,8 +10,15 @@ export const Navbar: FunctionComponent<Props> = () => {
|
||||
<h1>Our fancy header with navigation.</h1>
|
||||
<p>App version: {JSON.stringify(Config.version)}</p>
|
||||
<nav data-testid="nav">
|
||||
<Link to="/">Home</Link> <Link to="/about">About</Link>
|
||||
<Link to="/counter">Counter</Link>
|
||||
<Link to="/" data-testid="nav.home">
|
||||
Home
|
||||
</Link>{" "}
|
||||
<Link to="/about" data-testid="nav.about">
|
||||
About
|
||||
</Link>
|
||||
<Link to="/counter" data-testid="nav.counter">
|
||||
Counter
|
||||
</Link>
|
||||
<hr />
|
||||
</nav>
|
||||
</>
|
||||
|
Loading…
Reference in New Issue
Block a user