diff --git a/.eslintrc.json b/.eslintrc.json index 831be302..aa0278a0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,7 +1,8 @@ { "env": { "browser": true, - "es2021": true + "es2021": true, + "cypress/globals": true }, "extends": ["plugin:react/recommended", "airbnb", "prettier"], "parserOptions": { @@ -11,7 +12,7 @@ "ecmaVersion": "latest", "sourceType": "module" }, - "plugins": ["react", "prettier"], + "plugins": ["react", "prettier", "cypress"], "rules": { "prettier/prettier": "warn", "no-unused-vars": "warn", diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 00000000..48cd18f5 --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,51 @@ +# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs +# From https://github.com/dhxnveer/bhanwari-devi/blob/main/.github/workflows/tests.yml + +name: Node.js CI + +on: + push: + branches: [ "*" ] + pull_request: + types: [ opened, reopened ] + +jobs: + build: + name: test + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x, 15.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v3 + - name: Builds and tests ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - name: Set npm legacy-peer-deps + run: npm config set legacy-peer-deps true + - run: npm install + - name: Set Environment Variables + run: | + echo "VITE_API_URL=https://dev-join.navgurukul.org/api/" >> .env.development + echo "VITE_API_URL=https://join.navgurukul.org/api/" >> .env.production + - run: npm ci + - run: npm run build --if-present + env: + CI: false + - name: Run npm run dev + run: | + npm run dev & + sleep 2 + - name: Run Cypress tests + run: npx cypress run --config-file cypress.config.js + - name: Archive test artifacts + uses: actions/upload-artifact@v2 + if: always() # always upload videos, even if the test fails + with: + name: cypress-videos + path: cypress/videos diff --git a/AD-150-basic-details b/AD-150-basic-details new file mode 100644 index 00000000..6857a97b --- /dev/null +++ b/AD-150-basic-details @@ -0,0 +1,108 @@ + origin/AD-108-city-and-pin-code-boxes-have-no-validation + origin/AD-131-Added-Dantewala-District + origin/AD-143-create-test-pass-filter + origin/AD-150 + origin/AD-4-school-update-issue + origin/Add-Cypress-Testing + origin/Added-Close-Icon + origin/Boys_Admission_Closed + origin/Changes-in-campus-and-school + origin/Filter-By-School + origin/Fix-AD-122 + origin/Fix-AD103 + origin/Fix-DOB + origin/HEAD -> origin/main + origin/Invalid-entries-should-show-error-messages-in-real-time + origin/Lets-Go-Ahead-Button + origin/MUI-X-Install + origin/Mandatory-options + origin/Profile-Photo-Upload-Admin + origin/Questions-Answers-Attempt + origin/Small-Changes-In-Html + origin/Stages-Bug + origin/TestThatWork + origin/TestThatWork2 + origin/Test_FemaleJohn + origin/Udaipur_Campus + origin/added-campuses + origin/added-campuses-stages + origin/added-jashpur-campus + origin/added-sentry + origin/addedDonors + origin/arrow-issue + origin/basic-data-refresh-issue + origin/beforeDeadCodeRemoval + origin/campus-api + origin/campus-list + origin/changed-dob + origin/commit-for-deploy + origin/date-dev + origin/date-filter-issue + origin/dd-mm-yyyy + origin/demo-check + origin/dev + origin/dev-copy + origin/dev-revert + origin/dob-changed + origin/dob-format + origin/dob-format-change + origin/donor-issue + origin/donor-issue-for-new-school + origin/e2 + origin/enable-test-lahia + origin/feature-GA + origin/feature-googleAnalytics + origin/fix-AD-150---video-demo + origin/fix/AD-8-Stages-for-new-school + origin/fix/arrow + origin/fix/close-profile-prompt + origin/fix/date-filter + origin/fix/deleted-env-file + origin/fix/profile-picture + origin/fix/profile-update + origin/fix/school-filter + origin/fix/school-update + origin/fix/student-details-dob + origin/gh-pages + origin/hot-fix-AD-131-Dantewada + origin/kartikRevamp + origin/main + origin/new-main + origin/new-school-dashboard + origin/new-user + origin/new_registration + origin/new_user_register + origin/oldDeployBackup + origin/oldDevBackup + origin/overview + origin/overview-tab + origin/overview-task + origin/partner-group-list + origin/placementsSection + origin/remove-check-result + origin/resolved-refresing-basic-data-page + origin/retest-validation + origin/revert-449-school-dropdown-2 + origin/revert-463-Filter-By-School + origin/revert-483-Fix-AD103 + origin/revert-495-dev + origin/revert-496-dev + origin/revert-505-dev + origin/revert-506-dev + origin/school-dropdown + origin/school-dropdown-2 + origin/school-menu-bugs + origin/school-stages + origin/schoolmenu + origin/show-overview + origin/showMarks + origin/space-in-login-form-issue + origin/stages-school-students + origin/studentsDetailes + origin/surveyFormSelector + origin/to-date + origin/update-new-changes + origin/updated-dev + origin/updated-dev2 + origin/vercel-config + origin/vite-config diff --git a/cypress.config.js b/cypress.config.js new file mode 100644 index 00000000..a0eb17f6 --- /dev/null +++ b/cypress.config.js @@ -0,0 +1,7 @@ +const { defineConfig } = require("cypress"); + +module.exports = defineConfig({ + e2e: { + setupNodeEvents() {}, + }, +}); diff --git a/cypress/cypress/support/commands.js b/cypress/cypress/support/commands.js new file mode 100644 index 00000000..119ab03f --- /dev/null +++ b/cypress/cypress/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js 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) => { ... }) diff --git a/cypress/cypress/support/e2e.js b/cypress/cypress/support/e2e.js new file mode 100644 index 00000000..3a252243 --- /dev/null +++ b/cypress/cypress/support/e2e.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/e2e.js 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') diff --git a/cypress/e2e/chromeRecorder.cy.js b/cypress/e2e/chromeRecorder.cy.js new file mode 100644 index 00000000..70b47f56 --- /dev/null +++ b/cypress/e2e/chromeRecorder.cy.js @@ -0,0 +1,145 @@ +//Used chrome extenstion Cypress Chrome Recorder +import "cypress-file-upload"; + +const firstNames = [ + "John", + "Jane", + "David", + "Emily", + "Michael", + "Olivia", + "Daniel", + "Sophia", + "Matthew", + "Ava", +]; +const lastNames = [ + "Wick", + "Johnson", + "Brown", + "Davis", + "Wilson", + "Anderson", + "Taylor", + "Clark", + "Walker", + "Moore", +]; + +const getRandomValueFromArray = (array) => { + const randomIndex = Math.floor(Math.random() * array.length); + return array[randomIndex]; +}; + +const getRandomFirstName = () => getRandomValueFromArray(firstNames); + +const getRandomLastName = () => getRandomValueFromArray(lastNames); + +const getRandomPhoneNumber = () => { + const randomNumber = Math.floor(Math.random() * 900000000) + 100000000; + return `9${randomNumber.toString()}`; +}; + +const getRandomGmailAddress = () => { + const randomString = Math.random().toString(36).substring(7); + return `random${randomString}@gmail.com`; +}; + +const getRandomBirthday = () => { + const currentYear = new Date().getFullYear(); + const minYear = currentYear - 28; + const maxYear = currentYear - 17; + const year = Math.floor(Math.random() * (maxYear - minYear + 1)) + minYear; + const month = Math.floor(Math.random() * 12) + 1; + const day = Math.floor(Math.random() * 28) + 1; + return `${day.toString().padStart(2, "0")}/${month + .toString() + .padStart(2, "0")}/${year}`; +}; + +Cypress.on("uncaught:exception", () => false); + +describe("JohnWickTest", () => { + it("tests JohnWickTest", () => { + cy.viewport(1268, 937); + cy.visit("http://localhost:8080/"); + const randomPhoneNumber = getRandomPhoneNumber(); + const randomGmailAddress = getRandomGmailAddress(); + const randomBirthday = getRandomBirthday(); + const randomFirstName = getRandomFirstName(); + const randomLastName = getRandomLastName(); + cy.get("div:nth-of-type(3) > div:nth-of-type(1) input").click(); + cy.get("div:nth-of-type(3) > div:nth-of-type(1) input").type( + randomFirstName + ); + cy.get("div:nth-of-type(4) > div:nth-of-type(1) input").click(); + cy.get("div:nth-of-type(4) > div:nth-of-type(1) input").type( + randomLastName + ); + cy.get("div:nth-of-type(2) > div.MuiBox-root").click(); + cy.get("#app > div > div:nth-of-type(2)").click(); + cy.get("div:nth-of-type(4) > div:nth-of-type(2) input").click(); + cy.get("div:nth-of-type(4) > div:nth-of-type(2) input").type( + randomPhoneNumber + ); + cy.get("div > div > div > div:nth-of-type(2) button").click(); + cy.get("#mui-component-select-Language").click(); + cy.get('li[data-value="en"]').click(); + // cy.contains("English").click({ force: true }); English option is covered by + //another element, comment code only work for hindi and marathi because + //those are not covered by other code. Tried other ways too. + //while use force true, the drop down menu will not go away, cannot process to next step. + //So be specific like: li[data-value="en"] so it works, en can replace with hi,mr. + cy.get("#mui-component-select-Language").should("contain", "English"); + cy.get("div:nth-of-type(12) > button").click(); + cy.get("div:nth-of-type(11) > button").click(); + cy.get("div:nth-of-type(11) > button").click(); + cy.get("div:nth-of-type(2) > div div.MuiContainer-root").click(); + cy.get("div:nth-child(4) > div input").click(); + cy.get("div:nth-child(4) > div input").type(randomBirthday); + cy.get("div:nth-child(7) > div input").click(); + cy.get("div:nth-child(7) > div input").type(randomGmailAddress); + cy.get("#gender").click(); + cy.contains("Female").click(); // can replace with transgender but not male + cy.get("#gender").should("contain", "Female"); //male is full + // profile picture + const fileName = "1mb.png"; + cy.fixture(fileName).then((fileContent) => { + cy.get('[data-cy="imageInput"]').attachFile({ + fileContent, + fileName, + mimeType: "image/jpeg", + }); + }); + cy.get("button:nth-child(3)").click(); + cy.get("#mui-component-select-state").click(); + cy.get("li:nth-of-type(5)").click(); + cy.get("#mui-component-select-district").click(); + cy.get("#menu-district > div.MuiBackdrop-root").click(); + cy.get("#mui-component-select-district").click(); + cy.get("li:nth-of-type(3)").click(); + cy.get("#city").click(); + cy.get("#city").type("Wash.D.C"); + cy.get("#pin_code").click(); + cy.get("#pin_code").type("456001"); + cy.get("#mui-component-select-current_status").click(); + cy.get("li:nth-of-type(4)").click(); + cy.get("#mui-component-select-qualification").click(); + cy.get("li:nth-of-type(5)").click(); + cy.get("div:nth-child(7) > div > div").click(); + cy.get("div:nth-child(7) > div > div").type("99.99"); + cy.get("div:nth-child(8) > div > div").click(); + cy.get("div:nth-child(8) > div > div").type("99.99"); + cy.get("#mui-component-select-school_medium").click(); + cy.get("li:nth-of-type(3)").click(); + cy.get("#mui-component-select-caste").click(); + cy.get("li:nth-of-type(4)").click(); + cy.get("#mui-component-select-religion").click(); + cy.get("li:nth-of-type(8)").click(); + cy.get("#mui-component-select-religion").click(); + cy.get("li:nth-of-type(7)").click(); + cy.get( + "#app > div > div:nth-of-type(2) button.MuiButton-contained" + ).click(); + }); +}); diff --git a/cypress/e2e/landingPage.cy.js b/cypress/e2e/landingPage.cy.js new file mode 100644 index 00000000..d2ac9e39 --- /dev/null +++ b/cypress/e2e/landingPage.cy.js @@ -0,0 +1,121 @@ +/// + +Cypress.on("uncaught:exception", () => false); + +// TODO: Make links dynamic +beforeEach(() => { + cy.visit("http://localhost:8080/"); +}); + +describe("Section 1: Landing page", () => { + // TS101 + it("should display the logo top left, should redirect user to home page when logo is clicked", () => { + // display logo top left + cy.get('[data-cy="logo"]') + .should("have.css", "top", "0px") + .should("have.css", "left", "0px"); + + // clicking logo should redirect user to home page + cy.visit("http://localhost:8080/test/instructions"); + cy.get('[data-cy="logo"]').click(); + + cy.url().should("equal", "http://localhost:8080/"); + }); + // TS101 + it("should have a language dropdown with the options English, Hindi and Marathi: Verify language change", () => { + cy.get(`[data-cy="lang-dropdown"]`).should("have.value", ""); + + // open the select + cy.get(`[data-cy="lang-dropdown"]`).click(); + + // select English, verify change of language + cy.get(`[data-cy="en"]`).click(); + cy.get('[data-cy="title"]').contains("Start Admisssion Test"); + + // select Hindin verify change of language + cy.get(`[data-cy="hi"]`).click(); + cy.get('[data-cy="title"]').contains("परीक्षा शुरू करें"); + + // select Marathi, change language + cy.get("#appheader > div > div:nth-child(1) > div > div").click(); + cy.get('[data-value="ma"]').click(); + cy.get('[data-cy="title"]').contains("प्रवेश परीक्षा सुरू करा"); + }); + + // TS103 + it("should type in user's first and last names, submit form and verify move to test instructions", () => { + cy.fixture("users").then((users) => { + const user = users[0]; + + cy.get(`[data-cy="firstName-input"]`).type(user.firstName); + cy.get(`[data-cy="lastName-input"]`).type(user.lastName); + cy.get(`[data-cy="mobileNumber-input"]`).type(user.mobileNumber); + cy.get(`[data-cy="submitButton"]`) + .click() + .url() + .should("include", "test/instructions"); + }); + }); + + // TS103_02 + it("should type in user's first and last names AND MIDDLE NAME, submit form and verify move to test instructions", () => { + cy.fixture("users").then((users) => { + const user = users[0]; + + cy.get(`[data-cy="firstName-input"]`).type(user.firstName); + // Middle NAME + cy.get(`[data-cy="middleName-input"]`).type(user.middleName); + + cy.get(`[data-cy="lastName-input"]`).type(user.lastName); + cy.get(`[data-cy="mobileNumber-input"]`).type(user.mobileNumber); + cy.get(`[data-cy="submitButton"]`) + .click() + .wait(1000) + .url() + .should("include", "test/instructions"); + }); + }); + + // TS105 + it("should submit button with invalid data, verify notification to user, URL should not change", () => { + // get the url before submit button is clicked + cy.url().then((urlBeforeSubmit) => { + cy.get(`[data-cy=submitButton]`).click(); + + // snackbar + cy.get('[data-cy="error-bar"]'); + + // get the url after submit button is clicked + cy.url().then((urlAfterSubmit) => { + // assert the URL before and after are the same + expect(urlBeforeSubmit).to.equal(urlAfterSubmit); + }); + }); + }); + + // TS105 Submit with invalid phone number + it("should submit button with invalid data, verify notification to user, URL should not change", () => { + cy.fixture("users").then((users) => { + const user = users[0]; + + // get the url before submit button is clicked + cy.url().then((urlBeforeSubmit) => { + // enter valid inputs for, first middle and last names: Invalid # Number + cy.get(`[data-cy="firstName-input"]`).type(user.firstName); + cy.get(`[data-cy="middleName-input"]`).type(user.middleName); + cy.get(`[data-cy="lastName-input"]`).type(user.lastName); + + cy.get(`[data-cy=submitButton]`).click(); + + // snackbar + cy.get('[data-cy="error-bar"]'); + + // get the url after submit button is clicked + cy.url().then((urlAfterSubmit) => { + // assert the URL before and after are the same + expect(urlBeforeSubmit).to.equal(urlAfterSubmit); + }); + }); + }); + }); +}); diff --git a/cypress/e2e/studentDetails.cy.js b/cypress/e2e/studentDetails.cy.js new file mode 100644 index 00000000..6f1a395d --- /dev/null +++ b/cypress/e2e/studentDetails.cy.js @@ -0,0 +1,151 @@ +/// + +Cypress.on("uncaught:exception", () => false); + +beforeEach(() => { + cy.visit("http://localhost:8080/test/studentdetails"); + + // Inputs + cy.get('[data-cy="firstName-input"]').as("firstNameInput"); + cy.get('[data-cy="middleName-input"]').as("middleNameInput"); + cy.get('[data-cy="lastName-input"]').as("lastNameInput"); + cy.get('[data-cy="email-input"]').as("emailInput"); + cy.get('form > .MuiPaper-root > [tabindex="0"]').as("nextButton"); + cy.get("#mui-1").as("dobDatePicker"); + cy.get('[data-cy="waInput"]').as("whatsAppNumberInput"); + cy.get('[data-cy="altInput"]').as("alternateNumberInput"); + cy.get('[data-cy="genderDropdown"]').as("genderDropdown"); + + // Input feedback + cy.get("#FirstName-helper-text").as("firstNameFeedback"); + cy.get("#MiddleName-helper-text").as("middleNameFeedback"); + cy.get("#LastName-helper-text").as("lastNameFeedback"); + cy.get("#FirstName-helper-text").as("numberFeedback"); + cy.get("#mui-2-helper-text").as("emailFeedback"); + cy.get("#mui-1-helper-text").as("dobFeedback"); + cy.get("#whatsapp-helper-text").as("whatsAppNumFeedback"); + cy.get("#AlternateNumber-helper-text").as("altNumberFeedback"); +}); + +describe("Section 3: Basic Details", () => { + context("Form validation testing", () => { + describe("Verify error feedback", () => { + it("should verify the first name, last name & email fields with invalid inputs", () => { + // Submit form (No input) + cy.get("@nextButton").click(); + cy.get("@firstNameFeedback").contains("Enter First Name"); + cy.get("@lastNameFeedback").contains("Enter Last Name"); + cy.get("@emailFeedback").contains("Enter Email"); + }); + it("Should verify an invalid email", () => { + cy.get("@emailInput").type("invalid#gmail.com"); + cy.get("@nextButton").click(); + + cy.get("@emailInput").contains("Enter Valid Email"); + }); + }); + describe("Verify fist name, last name, & email fields", () => { + it("should verify the first name, last name & email fields with valid inputs", () => { + cy.fixture("users.json").then((users) => { + const user = users[0]; + + cy.get("@firstNameInput").type(user.firstName); + cy.get("@lastNameInput").type(user.lastName); + cy.get("@emailInput").type(user.email); + // Submit form + cy.get("@nextButton").click(); + + // Check if input is valid by checking the text value + cy.get("@firstNameInput").should("not.have.class", "Mui-error"); + cy.get("@lastNameInput").should("not.have.class", "Mui-error"); + cy.get("@emailInput").should("not.have.class", "Mui-error"); + }); + }); + }); + describe("Verify the datepicker", () => { + it("Should verify the user age is between 17 & 28 years", () => { + // Invalid age lower than 17 + cy.get("@dobDatePicker").click().type("13/10/2006"); + cy.get("@nextButton").click(); + cy.get("@dobFeedback").should("have.class", "Mui-error"); + + // valid age between 17-28 years + cy.get("@dobDatePicker").click().clear().type("13/10/2005"); + cy.get("@nextButton").click(); + cy.get("@dobFeedback").should("not.have.class", "Mui-error"); + + // Invalid age higher than 28 years + cy.get("@dobDatePicker").click().clear().type("13/10/1993"); + cy.get("@nextButton").click(); + cy.get("@dobFeedback").should("have.class", "Mui-error"); + }); + }); + describe("Verify Whatsapp and alternate number input fields", () => { + it("Should verify the number field validations are working", () => { + cy.fixture("users.json").then((users) => { + const user = users[0]; + // Valid inputs + cy.get("@whatsAppNumberInput").type(user.mobileNumber); + cy.get("@nextButton").click(); + cy.get("@whatsAppNumFeedback").should("not.have.class", "Mui-error"); + + cy.get("@alternateNumberInput").type(user.alternateNumber); + cy.get("@nextButton").click(); + cy.get("@altNumberFeedback").should("not.have.class", "Mui-error"); + + // Invalid inputs shorter than 10 digits + cy.get("@whatsAppNumberInput").clear().type("1"); + cy.get("@nextButton").click(); + cy.get("@whatsAppNumFeedback").should("have.class", "Mui-error"); + + cy.get("@alternateNumberInput").clear().type("1"); + cy.get("@nextButton").click(); + cy.get("@altNumberFeedback").should("have.class", "Mui-error"); + + // Invalid inputs greater than 10 digits + cy.get("@whatsAppNumberInput").clear().type(`${user.mobileNumber}1`); + cy.get("@nextButton").click(); + cy.get("@whatsAppNumFeedback").should("have.class", "Mui-error"); + + cy.get("@alternateNumberInput") + .clear() + .type(`${user.alternateNumber}1`); + cy.get("@nextButton").click(); + cy.get("@altNumberFeedback").should("have.class", "Mui-error"); + }); + }); + }); + describe("Verify gender dropdown functionality", () => { + it("Should verify that an empty gender dropdown does not allow the use of nextButton", () => { + cy.get("@nextButton").click(); + cy.get('[data-cy="genderFeedback"]').contains( + "Please specify your gender" + ); + }); + it("Should verify the functionality of the gender dropdown", () => { + cy.get("@genderDropdown").should("have.value", ""); + + // male dropdown input + cy.get("@genderDropdown").click(); + cy.get('[data-value="male"]').click(); + cy.get("@genderDropdown") + .find(">input") + .should("have.attr", "value", "male"); + + // female dropdown input + cy.get("@genderDropdown").click(); + cy.get('[data-value="female"]').click(); + cy.get("@genderDropdown") + .find(">input") + .should("have.attr", "value", "female"); + + // transgender dropdown input + cy.get("@genderDropdown").click(); + cy.get('[data-value="trans"]').click(); + cy.get("@genderDropdown") + .find(">input") + .should("have.attr", "value", "trans"); + }); + }); + }); +}); diff --git a/cypress/e2e/testInstructions.cy.js b/cypress/e2e/testInstructions.cy.js new file mode 100644 index 00000000..370869c6 --- /dev/null +++ b/cypress/e2e/testInstructions.cy.js @@ -0,0 +1,48 @@ +/// +beforeEach(() => { + cy.visit("http://localhost:8080/test/instructions"); +}); + +// TS201 +describe("Section 2: Test Instructions", () => { + context("Language dropdown", () => { + it("should have a language dropdown with the options English, Hindi and Marathi: Verify language change", () => { + cy.get('[data-cy="lang-dropdown"]').should("have.value", ""); + + // open the select + cy.get('[data-cy="lang-dropdown"]').click(); + + // select English, verify change of language + cy.get('[data-cy="en"]').click(); + cy.get('[data-cy="title"]').contains("Select Your Language"); + + // select Hindin verify change of language + cy.get("#mui-component-select-Language").click(); + cy.get('li[data-value="hi"]').click(); + cy.get('[data-cy="title"]').contains("अपनी भाषा चुने"); + + // select Marathi, change language + cy.get("#mui-component-select-Language").click(); + cy.get('li[data-value="ma"]').click(); + cy.get('[data-cy="title"]').contains("तुमची भाषा निवडा"); + }); + }); + + context("Next step button functionality", () => { + it("should move to next step when (Step) button is clicked", () => { + // Lets go ahead button + cy.get('[data-cy="nextStepButton"]').click(); + cy.get(`[data-cy="heading`).contains("NavGurukul Entrance Test"); + + // Im ready button + cy.get('[data-cy="nextStepButton"]').click(); + cy.get('[data-cy="heading"]').contains("Read Carefully"); + + // Start the text button + cy.get('[data-cy="startTestButton"]') + .click() + .url() + .should("contain", "/test/studentdetails"); + }); + }); +}); diff --git a/cypress/fixtures/1mb.png b/cypress/fixtures/1mb.png new file mode 100644 index 00000000..533fb8bb Binary files /dev/null and b/cypress/fixtures/1mb.png differ diff --git a/cypress/fixtures/test-image.jpg b/cypress/fixtures/test-image.jpg new file mode 100644 index 00000000..da62b411 Binary files /dev/null and b/cypress/fixtures/test-image.jpg differ diff --git a/cypress/fixtures/users.json b/cypress/fixtures/users.json new file mode 100644 index 00000000..ee04c701 --- /dev/null +++ b/cypress/fixtures/users.json @@ -0,0 +1,11 @@ +[ + { + "firstName": "Jane", + "middleName": "Eva", + "lastName": "Doe", + "mobileNumber": "9999999999", + "alternateNumber": "9999999999", + "email": "JaneEvaDoe@gmail.com", + "dob": "10/13/2004" + } +] diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 00000000..119ab03f --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js 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) => { ... }) diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js new file mode 100644 index 00000000..3a252243 --- /dev/null +++ b/cypress/support/e2e.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/e2e.js 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') diff --git a/cypress/videos/studentDetails.cy.js.mp4 b/cypress/videos/studentDetails.cy.js.mp4 new file mode 100644 index 00000000..e8e1c521 Binary files /dev/null and b/cypress/videos/studentDetails.cy.js.mp4 differ diff --git a/package.json b/package.json index 03e43e22..3d68279b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ "lint": "eslint src --fix", "checklint": "eslint src", "lint-staged": "lint-staged", - "prepare": "husky install" + "prepare": "husky install", + "cypress:open": "cypress open", + "cypress:run": "cypress run" }, "lint-staged": { "*.{js,jsx}": [ @@ -76,7 +78,7 @@ "react-redux": "^7.2.6", "react-router-dom": "^6.2.2", "react-select": "^5.2.2", - "react-slick": "^0.29.0", + "react-slick": "^0.28.1", "react-spinner-material": "^1.4.0", "react-timer-hook": "^3.0.5", "react-youtube": "^7.14.0", @@ -85,9 +87,12 @@ }, "devDependencies": { "@vitejs/plugin-react": "^1.2.0", + "cypress": "^12.9.0", + "cypress-file-upload": "^5.0.8", "eslint": "^8.11.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", + "eslint-plugin-cypress": "^2.13.3", "eslint-plugin-import": "^2.25.4", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-prettier": "^4.0.0", diff --git a/src/components/layout/Header.jsx b/src/components/layout/Header.jsx index b3bc413a..7b7f2b54 100644 --- a/src/components/layout/Header.jsx +++ b/src/components/layout/Header.jsx @@ -147,6 +147,7 @@ const Header = () => { > ngLogo { > Select Language )} @@ -256,7 +264,7 @@ const Header = () => { ) : ( )} diff --git a/src/components/muiTables/ServerSidePagination.jsx b/src/components/muiTables/ServerSidePagination.jsx index fee687a1..5f6fedea 100644 --- a/src/components/muiTables/ServerSidePagination.jsx +++ b/src/components/muiTables/ServerSidePagination.jsx @@ -87,9 +87,9 @@ const ServerSidePagination = ({ value === "All" ? [...newData] : [ - ...newData, - { key: keys[query], value: encodeURIComponent(value) }, - ], + ...newData, + { key: keys[query], value: encodeURIComponent(value) }, + ], }; const { filterColumns: newColumns } = newState; const newUrl = await filterColumns.reduce((cUrl, filterColumn, index) => { @@ -137,23 +137,20 @@ const ServerSidePagination = ({ let body = ""; columns.forEach((col, colInx) => { if (col.name === "donor") { - body += `"${ - nStudent.donor !== null && nStudent.donor !== undefined + body += `"${nStudent.donor !== null && nStudent.donor !== undefined ? nStudent.donor.map((donor) => donor.donor).join(", ") : "" - }",`; + }",`; } else if (colInx === columns.length - 1) - body += `"${ - !nStudent[col.name] || nStudent[col.name] === undefined + body += `"${!nStudent[col.name] || nStudent[col.name] === undefined ? " " : nStudent[col.name] - }"`; + }"`; else - body += `"${ - !nStudent[col.name] || nStudent[col.name] === undefined + body += `"${!nStudent[col.name] || nStudent[col.name] === undefined ? " " : nStudent[col.name] - }",`; + }",`; }); return body; }) @@ -233,7 +230,7 @@ const ServerSidePagination = ({ return getfilterApi(columnChanged, filterValue); } - setFilters({ filterColumns: [], url: `${baseURL}students ? ` }); + setFilters({ filterColumns: [], url: `${baseURL}students?` }); }, responsive: "vertical", rowsPerPageOptions: [10, 50, 100], diff --git a/src/components/onlineTest/Instructions/index.jsx b/src/components/onlineTest/Instructions/index.jsx index b23f9899..4f7ebeb1 100644 --- a/src/components/onlineTest/Instructions/index.jsx +++ b/src/components/onlineTest/Instructions/index.jsx @@ -29,7 +29,7 @@ const tutorialSteps = [ }, subHadding: { // old:"Select Your Languge/ अपनी भाषा चुने", - en: "Select Your Languge", + en: "Select Your Language", hi: "अपनी भाषा चुने", ma: "तुमची भाषा निवडा", }, @@ -39,7 +39,7 @@ const tutorialSteps = [ inputField: true, button: { // old:"Aage chalein", - en: "Let's go Ahead ", + en: "Let's go Ahead", hi: "आगे बढ़ो", ma: "पुढे जा", }, @@ -219,12 +219,12 @@ const TestInstructions = () => {
- + {tutorialSteps[activeStep].heading[lang]} - + {tutorialSteps[activeStep].subHadding?.[lang]} @@ -269,14 +269,21 @@ const TestInstructions = () => { Choose your language @@ -284,6 +291,7 @@ const TestInstructions = () => { {tutorialSteps[activeStep].button ? (