From e81f4f8404016aab2d87a921acdd564fb9e8372f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Wed, 24 Apr 2024 19:07:46 +0200 Subject: [PATCH 01/12] test --- tests/unit/SignIn.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/SignIn.spec.js b/tests/unit/SignIn.spec.js index b2752627..f20d25fc 100644 --- a/tests/unit/SignIn.spec.js +++ b/tests/unit/SignIn.spec.js @@ -30,7 +30,7 @@ describe('SignIn', () => { return Promise.resolve() }) - const emailInput = screen.getByLabelText(/E-mail/i) + // const emailInput = screen.getByLabelText(/E-mail/i) await fireEvent.update(emailInput, 'valid-email') const passwordInput = screen.getByLabelText(/Password/i, { selector: 'input' }) await fireEvent.update(passwordInput, 'valid-password') From a0fafe3f2ed69ea7a272b1d6fee07e933196a368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Wed, 24 Apr 2024 19:10:10 +0200 Subject: [PATCH 02/12] revert commit --- tests/unit/SignIn.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/SignIn.spec.js b/tests/unit/SignIn.spec.js index f20d25fc..b2752627 100644 --- a/tests/unit/SignIn.spec.js +++ b/tests/unit/SignIn.spec.js @@ -30,7 +30,7 @@ describe('SignIn', () => { return Promise.resolve() }) - // const emailInput = screen.getByLabelText(/E-mail/i) + const emailInput = screen.getByLabelText(/E-mail/i) await fireEvent.update(emailInput, 'valid-email') const passwordInput = screen.getByLabelText(/Password/i, { selector: 'input' }) await fireEvent.update(passwordInput, 'valid-password') From 4e241108af0218fec25cbf7b8b876168e300e698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Thu, 2 May 2024 21:24:59 +0200 Subject: [PATCH 03/12] include cypress testing library in the project --- cypress/support/commands.js | 4 +++- jsconfig.json | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 66ea16ef..3751eb0c 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -22,4 +22,6 @@ // // // -- This will overwrite an existing command -- -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) \ No newline at end of file +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) + +import '@testing-library/cypress/add-commands' diff --git a/jsconfig.json b/jsconfig.json index 486c7bed..1ea48a97 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -3,6 +3,7 @@ "baseUrl": "./", "paths": { "@/*": ["src/*"] - } + }, + "types": ["cypress", "@testing-library/cypress"] } } From f456bd542cfd9d88a7c875e9cb7f2c5f64fb8a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sat, 4 May 2024 11:09:43 +0200 Subject: [PATCH 04/12] firebase auth utils for cypress --- cypress.config.js | 9 +- cypress/fixtures/authUser.json | 12 +++ cypress/fixtures/example.json | 5 -- cypress/support/commands.js | 11 +++ cypress/support/commands/auth.js | 139 +++++++++++++++++++++++++++++++ 5 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 cypress/fixtures/authUser.json delete mode 100644 cypress/fixtures/example.json create mode 100644 cypress/support/commands/auth.js diff --git a/cypress.config.js b/cypress.config.js index 97f47c41..54c7ff14 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -1,4 +1,5 @@ -const { defineConfig } = require("cypress"); +const { defineConfig } = require('cypress') +require('dotenv').config() module.exports = defineConfig({ e2e: { @@ -6,4 +7,8 @@ module.exports = defineConfig({ // implement node event listeners here }, }, -}); + env: { + // add environment variables here + ...process.env, + }, +}) diff --git a/cypress/fixtures/authUser.json b/cypress/fixtures/authUser.json new file mode 100644 index 00000000..8f766a6c --- /dev/null +++ b/cypress/fixtures/authUser.json @@ -0,0 +1,12 @@ +{ + "email": "ruxailab@ruxailab.com", + "password": "ruxailab1234", + "data": { + "accessLevel": 1, + "email" : "ruxailab@ruxailab.com", + "myAnswers": {}, + "myTests": {}, + "notifications": [] + }, + "collection": "users" +} diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json deleted file mode 100644 index 02e42543..00000000 --- a/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 3751eb0c..16f1fa20 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -25,3 +25,14 @@ // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) import '@testing-library/cypress/add-commands' +import { deleteUser, + logInWithEmailAndPassword, + logOut, + signUpWithEmailAndPassword } + from './commands/auth' + + +Cypress.Commands.add('deleteUser', deleteUser) +Cypress.Commands.add('login', logInWithEmailAndPassword) +Cypress.Commands.add('logout', logOut) +Cypress.Commands.add('signup', signUpWithEmailAndPassword) diff --git a/cypress/support/commands/auth.js b/cypress/support/commands/auth.js new file mode 100644 index 00000000..584d199c --- /dev/null +++ b/cypress/support/commands/auth.js @@ -0,0 +1,139 @@ +import { initializeApp } from 'firebase/app' +import { + getAuth, + connectAuthEmulator, + deleteUser as deleteUserAuth, + signInWithEmailAndPassword, + signOut, + createUserWithEmailAndPassword, +} from 'firebase/auth' +import { + getFirestore, + connectFirestoreEmulator, + doc, + setDoc, + deleteDoc, +} from 'firebase/firestore' + +const authUser = require('../../fixtures/authUser.json') + +const firebaseConfig = { + apiKey: Cypress.env('VUE_APP_FIREBASE_API_KEY'), + authDomain: Cypress.env('VUE_APP_FIREBASE_AUTH_DOMAIN'), + storageBucket: Cypress.env('VUE_APP_FIREBASE_STORAGE_BUCKET'), + projectId: Cypress.env('VUE_APP_FIREBASE_PROJECT_ID'), + appId: Cypress.env('VUE_APP_FIREBASE_APP_ID'), +} + +const firebaseApp = initializeApp(firebaseConfig) +const auth = getAuth(firebaseApp) +const db = getFirestore(firebaseApp) +if (window.Cypress) { + connectAuthEmulator(auth, 'http://localhost:9099') + connectFirestoreEmulator(db, 'localhost', 8081) +} + +/** + * Delete the currently logged in user + * @returns {Promise} + */ +export const deleteUser = async () => { + try { + if (!auth.currentUser) { + throw new Error('No user is logged in') + } + const { collection } = authUser + const currentUser = auth.currentUser + await deleteDocById(collection, currentUser.uid) + await deleteUserAuth(auth.currentUser) + console.info(`Deleted user with ID "${currentUser.uid}"`) + } catch (err) { + console.error(err) + alert(err.message) + } +} + +/** + * Log in with email and password + * @param email + * @param password + * @returns {Promise} + */ +export const logInWithEmailAndPassword = async (email, password) => { + try { + await signInWithEmailAndPassword(auth, email, password).then(() => { + console.info(`Logged in as "${email}"`) + }) + } catch (err) { + console.error(err) + alert(err.message) + } +} + +/** + * Log out the currently logged in user + * @returns {Promise} + */ +export const logOut = async () => { + try { + await signOut(auth).then(() => { + console.info('Logged out') + }) + } catch (err) { + console.error(err) + alert(err.message) + } +} + +/** + * Sign up with email and password + * @param email + * @param password + * @returns {Promise} + */ +export const signUpWithEmailAndPassword = async (email, password) => { + try { + const { user } = await createUserWithEmailAndPassword(auth, email, password) + console.info(`Signed up as "${email}" with user ID "${user.uid}"`) + const { data, collection } = authUser + await createDoc(collection, user.uid, data) + } catch (err) { + console.error(err) + alert(err.message) + } +} + +/** + * Create a document in a collection + * @param col + * @param docId + * @param data + * @returns {Promise} + */ +export const createDoc = async (col, docId, data) => { + try { + const ref = doc(db, `${col}/${docId}`) + await setDoc(ref, data) + } catch (err) { + console.error(err) + alert(err.message) + } +} + +/** + * Delete a document by ID + * @param col + * @param docId + * @returns {Promise} + */ +export const deleteDocById = async (col, docId) => { + try { + const ref = doc(db, `${col}/${docId}`) + await deleteDoc(ref) + } catch (err) { + console.error(err) + alert(err.message) + } +} + + From 15552d03ce10bb0939c66222cb98ddb02381f31b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sat, 4 May 2024 16:10:58 +0200 Subject: [PATCH 05/12] e2e auth tests --- cypress.config.js | 2 + cypress/e2e/auth.spec.cy.js | 67 ++++++++++++++++++++++++++++++++ cypress/fixtures/authUser.json | 1 + cypress/support/commands/auth.js | 13 +++---- 4 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 cypress/e2e/auth.spec.cy.js diff --git a/cypress.config.js b/cypress.config.js index 54c7ff14..9313118a 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -2,6 +2,7 @@ const { defineConfig } = require('cypress') require('dotenv').config() module.exports = defineConfig({ + projectId: 'xmf2jf', e2e: { setupNodeEvents(on, config) { // implement node event listeners here @@ -10,5 +11,6 @@ module.exports = defineConfig({ env: { // add environment variables here ...process.env, + url: 'http://localhost:8080', }, }) diff --git a/cypress/e2e/auth.spec.cy.js b/cypress/e2e/auth.spec.cy.js new file mode 100644 index 00000000..8bcb31f6 --- /dev/null +++ b/cypress/e2e/auth.spec.cy.js @@ -0,0 +1,67 @@ +const authUser = require('../fixtures/authUser.json') +const url = Cypress.env('url') + +describe('Authentication Suite', () => { + describe('Registration', () => { + it('should allow a new user to register', () => { + cy.visit(url + '/signup') + const { email, password } = authUser + cy.get('form').findByLabelText(/e-mail/i).type(email) + cy.get('form').findByLabelText("Password").type(password) + cy.get('form').findByLabelText("Confirm your password").type(password) + cy.findByRole('button', {name: 'Sign-up'}).click() + cy.wait(500) + cy.contains(email) + cy.deleteUser(email, password) + }) + it('should reject registration with invalid password', () => { + cy.visit(url + '/signup') + const { email, invalidPassword } = authUser + cy.get('form').findByLabelText(/e-mail/i).type(email) + cy.get('form').findByLabelText("Password").type(invalidPassword) + cy.get('form').findByLabelText("Confirm your password").type(invalidPassword) + cy.findByRole('button', {name: 'Sign-up'}).click() + cy.contains('Password must be at least 6 characters') + }) + it('should reject registration when passwords do not match', () => { + cy.visit(url + '/signup') + const { email, password, invalidPassword } = authUser + cy.get('form').findByLabelText(/e-mail/i).type(email) + cy.get('form').findByLabelText("Password").type(password) + cy.get('form').findByLabelText("Confirm your password").type(invalidPassword) + cy.findByRole('button', {name: 'Sign-up'}).click() + cy.contains('Different passwords') + }) + }) + describe('Login', () => { + const { email, password } = authUser + beforeEach(() => { + cy.signup(email, password) + cy.logout() + cy.visit(url + '/signin') + }) + afterEach(() => { + cy.deleteUser(email, password) + }) + it('should allow a registered user to login', () => { + cy.get('form').findByLabelText(/e-mail/i).type(email) + cy.get('form').findByLabelText('Password').type(password) + cy.findByTestId('sign-in-button').click() + cy.wait(500) + cy.contains(email) + }) + it('should reject login with incorrect password', () => { + const { email, password, invalidPassword } = authUser + cy.get('form').findByLabelText(/e-mail/i).type(email) + cy.get('form').findByLabelText('Password').type(invalidPassword) + cy.findByTestId('sign-in-button').click() + cy.contains('Incorrect password') + }) + it('should reject login with unregistered email', () => { + cy.get('form').findByLabelText(/e-mail/i).type('noexist@noexist.com') + cy.get('form').findByLabelText('Password').type('noexist') + cy.findByTestId('sign-in-button').click() + cy.contains('Incorrect username or password') + }) + }) +}) diff --git a/cypress/fixtures/authUser.json b/cypress/fixtures/authUser.json index 8f766a6c..23f9dcd4 100644 --- a/cypress/fixtures/authUser.json +++ b/cypress/fixtures/authUser.json @@ -1,6 +1,7 @@ { "email": "ruxailab@ruxailab.com", "password": "ruxailab1234", + "invalidPassword": "123", "data": { "accessLevel": 1, "email" : "ruxailab@ruxailab.com", diff --git a/cypress/support/commands/auth.js b/cypress/support/commands/auth.js index 584d199c..26cf34e7 100644 --- a/cypress/support/commands/auth.js +++ b/cypress/support/commands/auth.js @@ -37,16 +37,13 @@ if (window.Cypress) { * Delete the currently logged in user * @returns {Promise} */ -export const deleteUser = async () => { +export const deleteUser = async (email, password) => { try { - if (!auth.currentUser) { - throw new Error('No user is logged in') - } + const { user } = await signInWithEmailAndPassword(auth, email, password) const { collection } = authUser - const currentUser = auth.currentUser - await deleteDocById(collection, currentUser.uid) - await deleteUserAuth(auth.currentUser) - console.info(`Deleted user with ID "${currentUser.uid}"`) + await deleteDocById(collection, user.uid) + await deleteUserAuth(user) + console.info(`Deleted user with ID "${user.uid}"`) } catch (err) { console.error(err) alert(err.message) From bf6f07f9a3bdc8f717b76ad12cda1eb607ad639e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sat, 4 May 2024 17:13:30 +0200 Subject: [PATCH 06/12] data-testid in sign in button --- src/views/public/SignInView.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/views/public/SignInView.vue b/src/views/public/SignInView.vue index 755ee78b..be588e37 100644 --- a/src/views/public/SignInView.vue +++ b/src/views/public/SignInView.vue @@ -34,6 +34,7 @@ Date: Sat, 4 May 2024 18:31:23 +0200 Subject: [PATCH 07/12] remove alerts form auth command --- cypress/support/commands/auth.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cypress/support/commands/auth.js b/cypress/support/commands/auth.js index 26cf34e7..f34db04b 100644 --- a/cypress/support/commands/auth.js +++ b/cypress/support/commands/auth.js @@ -34,7 +34,7 @@ if (window.Cypress) { } /** - * Delete the currently logged in user + * Delete the currently logged-in user * @returns {Promise} */ export const deleteUser = async (email, password) => { @@ -46,7 +46,6 @@ export const deleteUser = async (email, password) => { console.info(`Deleted user with ID "${user.uid}"`) } catch (err) { console.error(err) - alert(err.message) } } @@ -63,12 +62,11 @@ export const logInWithEmailAndPassword = async (email, password) => { }) } catch (err) { console.error(err) - alert(err.message) } } /** - * Log out the currently logged in user + * Log out the currently logged-in user * @returns {Promise} */ export const logOut = async () => { @@ -78,7 +76,6 @@ export const logOut = async () => { }) } catch (err) { console.error(err) - alert(err.message) } } @@ -96,7 +93,6 @@ export const signUpWithEmailAndPassword = async (email, password) => { await createDoc(collection, user.uid, data) } catch (err) { console.error(err) - alert(err.message) } } @@ -113,7 +109,6 @@ export const createDoc = async (col, docId, data) => { await setDoc(ref, data) } catch (err) { console.error(err) - alert(err.message) } } @@ -129,7 +124,6 @@ export const deleteDocById = async (col, docId) => { await deleteDoc(ref) } catch (err) { console.error(err) - alert(err.message) } } From aeb89a57298ffca56c42034f38eec06857b74aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sat, 4 May 2024 18:35:34 +0200 Subject: [PATCH 08/12] heuristic create test --- cypress/e2e/heuristic.spec.cy.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 cypress/e2e/heuristic.spec.cy.js diff --git a/cypress/e2e/heuristic.spec.cy.js b/cypress/e2e/heuristic.spec.cy.js new file mode 100644 index 00000000..a922e18d --- /dev/null +++ b/cypress/e2e/heuristic.spec.cy.js @@ -0,0 +1,31 @@ +const heuristic = require('../fixtures/heuristic.json') +const authUser = require('../fixtures/authUser.json') + +const url = Cypress.env('url') +const { email, password } = authUser + +describe('Heuristic test Suite', () => { + before('Signup into the app', () => { + cy.deleteUser(email, password) + cy.signup(email, password) + cy.login(email, password) + }) + after('Remove user', () => { + cy.deleteUser(email, password) + }) + describe('Create Heuristic Test', () => { + it('should allow a new test to create', () => { + cy.visit(url + '/testslist') + cy.findByTestId('create-test-btn').click() + cy.findByText('Create a blank test').click() + cy.findByText('Usability Heuristic').click() + + const { name, description } = heuristic + cy.findByLabelText(/Test name/i).type(name) + cy.findByLabelText(/Test Description/i).type(description) + cy.findByTestId('add-name-test-creation-btn').click() + + cy.contains(/Manager/i) + }) + }) +}) From 882ecf730ef94d0d342a610cb4c9f6062d6d3a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sat, 4 May 2024 18:35:41 +0200 Subject: [PATCH 09/12] heuristic create test --- cypress/fixtures/heuristic.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 cypress/fixtures/heuristic.json diff --git a/cypress/fixtures/heuristic.json b/cypress/fixtures/heuristic.json new file mode 100644 index 00000000..93fa06e0 --- /dev/null +++ b/cypress/fixtures/heuristic.json @@ -0,0 +1,4 @@ +{ + "name": "Heuristic Test", + "description": "This is a test of the heuristic test" +} From f306a603ba732620aef20fe87488d73216fcb1d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sat, 4 May 2024 18:35:58 +0200 Subject: [PATCH 10/12] add data-testid in components --- src/views/admin/CreateBlankView.vue | 1 + src/views/admin/DashboardView.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/src/views/admin/CreateBlankView.vue b/src/views/admin/CreateBlankView.vue index bc0eb651..fe1c861f 100644 --- a/src/views/admin/CreateBlankView.vue +++ b/src/views/admin/CreateBlankView.vue @@ -169,6 +169,7 @@ color="orange" class="ml-auto mt-4 mr-2 circleOrange" @click="validate()" + data-testid="add-name-test-creation-btn" > mdi-arrow-right diff --git a/src/views/admin/DashboardView.vue b/src/views/admin/DashboardView.vue index 50ae7efe..4d7a4d7c 100644 --- a/src/views/admin/DashboardView.vue +++ b/src/views/admin/DashboardView.vue @@ -16,6 +16,7 @@ v-bind="attrs" @click="goToCreateTestRoute()" v-on="on" + data-testid="create-test-btn" > mdi-plus From b699d0113101e0ed70e610920c7f3efdb953f566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Sat, 4 May 2024 18:36:40 +0200 Subject: [PATCH 11/12] update package.json --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 495a8e64..308bdee6 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ }, "devDependencies": { "@intlify/vue-i18n-loader": "^1.1.0", + "@testing-library/cypress": "^10.0.1", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/user-event": "12", @@ -60,7 +61,7 @@ "@vue/test-utils": "^1.3.0", "babel-eslint": "^8.2.6", "babel-plugin-transform-require-context": "^0.1.1", - "cypress": "^13.7.3", + "cypress": "^13.8.1", "eslint": "^6.7.2", "eslint-plugin-vue": "^6.2.2", "jsdoc": "^3.6.11", From 707aaa444a6b131d0cdeb25b879380e56e8787e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Beltra=CC=81n?= Date: Thu, 9 May 2024 20:05:15 +0200 Subject: [PATCH 12/12] include data-testid in button to create heruistic test --- src/views/admin/CreateBlankView.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/views/admin/CreateBlankView.vue b/src/views/admin/CreateBlankView.vue index 4f88c776..33dac776 100644 --- a/src/views/admin/CreateBlankView.vue +++ b/src/views/admin/CreateBlankView.vue @@ -169,6 +169,7 @@ color="orange" class="ml-auto mr-2 circleOrange" @click="validate()" + data-testid="add-name-test-creation-btn" > mdi-arrow-right