Rewrite old E2E tests to use fixture-based API mocking, eliminating need for real credentials

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 00:31:16 +08:00
parent dc0a98f819
commit 905f546227
12 changed files with 371 additions and 458 deletions

View File

@@ -1,71 +1,52 @@
import { loginWithFixtures } from '../../support/intercept';
const MSG_ACCOUNT_NOT_UNIQUE = 'Account has already been registered.';
describe('Account duplication check.', ()=>{
beforeEach(() => {
cy.visit('/account-admin');
const username = Cypress.env('user').username;
const password = Cypress.env('user').password;
cy.visit('/account-admin');
cy.get('input[id="account"]').type(username);
cy.get('input[id="password"]').type(password);
cy.get('button[type="submit"]').click();
});
describe('Account duplication check.', () => {
beforeEach(() => {
loginWithFixtures();
cy.visit('/account-admin');
cy.wait('@getUsers');
});
it('When an account is already existed, show the error message when the confirm button is clicked.', () => {
const testAccountName = '000000';
cy.contains('button', 'Create New').should('be.visible');
cy.contains('button', 'Create New').click();
// 在 id 為 input_account_field 的 input 元素內填入值
cy.get('#input_account_field').type(testAccountName);
cy.get('#input_name_field').type(testAccountName);
cy.get('#input_first_pwd').type(testAccountName);
cy.get('#input_second_pwd').type(testAccountName);
cy.get('.checkbox-and-text').first().find('div').first().click();
// 確保 Confirm 按鈕存在並可點擊
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
cy.contains('Account added').should('be.visible'); //表示帳號創建成功
it('When an account already exists, show error message on confirm.', () => {
const testAccountName = '000000';
cy.contains('span', 'Account').should('be.visible'); // 表示畫面轉導向成功,出現清單列表
// 接著,點選排序按鈕,排序將會造成生升冪排序,我們希望 000000 帳號排在第一個
// 找到包含 'Account' 的 span 元素
cy.get('span:contains("Account")')
.closest('th')
.find('span')
.not(':contains("Account")')
.first()
.click(); // 點選下一个兄弟 span 元素
// 等待,以確保頁面已完全渲染
cy.wait(1000);
// First creation: account doesn't exist yet
cy.intercept('GET', '/api/users/000000', {
statusCode: 404,
body: { detail: 'Not found' },
}).as('checkNewUser');
// 確認 000000 帳號是否出現在第一列
cy.get('tr').filter((index, tr) => {
// 遍歷所有的 tr 元素
const td = Cypress.$(tr).find('td').eq(0); // 找到第一個 td 元素
return td.text().trim() === '000000'; // 檢查其文本內容是否為 000000
}).first().should('exist'); // 確認至少有一個符合條件的 tr 存在
cy.contains('button', 'Create New').should('be.visible').click();
cy.get('#input_account_field').type(testAccountName);
cy.get('#input_name_field').type(testAccountName);
cy.get('#input_first_pwd').type(testAccountName);
cy.get('.checkbox-and-text').first().find('div').first().click();
// 接著又再次創建一個同樣名稱的帳號,企圖看是否出現錯誤訊息
cy.contains('button', 'Create New').should('be.visible');
cy.contains('button', 'Create New').click();
// 在 id 為 input_account_field 的 input 元素內填入值
cy.get('#input_account_field').type(testAccountName);
cy.get('#input_name_field').type(testAccountName);
cy.get('#input_first_pwd').type(testAccountName);
cy.get('#input_second_pwd').type(testAccountName);
cy.get('.checkbox-and-text').first().find('div').first().click();
// 確保 Confirm 按鈕存在並可點擊
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
cy.contains('span', MSG_ACCOUNT_NOT_UNIQUE).should('be.visible');
});
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
cy.wait('@postUser');
cy.contains('Account added').should('be.visible');
// Second creation: now account exists — override to return 200
cy.intercept('GET', '/api/users/000000', {
statusCode: 200,
body: { username: '000000', name: '000000', is_admin: false, is_active: true, roles: [] },
}).as('checkExistingUser');
cy.contains('button', 'Create New').should('be.visible').click();
cy.get('#input_account_field').type(testAccountName);
cy.get('#input_name_field').type(testAccountName);
cy.get('#input_first_pwd').type(testAccountName);
cy.get('.checkbox-and-text').first().find('div').first().click();
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
cy.contains(MSG_ACCOUNT_NOT_UNIQUE).should('be.visible');
});
});

View File

@@ -1,44 +1,30 @@
import { getRandomInt } from '../../../src/utils/jsUtils';
const MSG_PWD_NOT_MATCHED = 'Confirm Password does not match.';
import { loginWithFixtures } from '../../support/intercept';
describe('Confirm that two input passwords are equal.', ()=>{
beforeEach(() => {
cy.visit('/account-admin');
const username = Cypress.env('user').username;
const password = Cypress.env('user').password;
cy.visit('/account-admin');
cy.get('input[id="account"]').type(username);
cy.get('input[id="password"]').type(password);
cy.get('button[type="submit"]').click();
});
describe('Password validation on create account.', () => {
beforeEach(() => {
loginWithFixtures();
cy.visit('/account-admin');
cy.wait('@getUsers');
});
it('Confirm that when creating an account, the two input password fields are equal; otherwise, show the message.', () => {
cy.contains('button', 'Create New').should('be.visible');
cy.contains('button', 'Create New').click();
const randomNumber = getRandomInt(1000);
// 將整數轉換為四位數字串,並補零
const fourDigitString = randomNumber.toString().padStart(4, '0');
it('When password is too short, confirm button stays disabled.', () => {
cy.contains('button', 'Create New').should('be.visible').click();
// 將 'unit-test-' 和生成的四位數字串組合
const inputValue = `unit-test-${fourDigitString}`;
cy.get('#input_account_field').type('unit-test-0001');
cy.get('#input_name_field').type('unit-test-0001');
// Password shorter than 6 characters
cy.get('#input_first_pwd').type('aaa');
// 在 id 為 input_account_field 的 input 元素內填入值
cy.get('#input_account_field').type(inputValue);
cy.get('#input_name_field').type(inputValue);
cy.get('#input_first_pwd').type('aaaaaa');
cy.get('#input_second_pwd').type('bbbbbb');
cy.contains('button', 'Confirm').should('be.disabled');
});
// 確保 Confirm 按鈕存在並可點擊
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
it('When password meets minimum length, confirm button enables.', () => {
cy.contains('button', 'Create New').should('be.visible').click();
cy.contains(MSG_PWD_NOT_MATCHED).should('be.visible');
});
cy.get('#input_account_field').type('unit-test-0001');
cy.get('#input_name_field').type('unit-test-0001');
cy.get('#input_first_pwd').type('aaaaaa');
cy.contains('button', 'Confirm').should('be.enabled');
});
});

View File

@@ -1,42 +1,36 @@
import { getRandomInt } from '../../../src/utils/jsUtils';
import { loginWithFixtures } from '../../support/intercept';
describe('Create an Account', ()=>{
beforeEach(() => {
cy.visit('/account-admin');
const username = Cypress.env('user').username;
const password = Cypress.env('user').password;
cy.visit('/account-admin');
cy.get('input[id="account"]').type(username);
cy.get('input[id="password"]').type(password);
cy.get('button[type="submit"]').click();
});
describe('Create an Account', () => {
beforeEach(() => {
loginWithFixtures();
// Override: new usernames should return 404 (account doesn't exist yet)
cy.intercept('GET', '/api/users/unit-test-*', {
statusCode: 404,
body: { detail: 'Not found' },
}).as('checkNewUser');
cy.visit('/account-admin');
cy.wait('@getUsers');
});
it('Create a new account; role is admin; should appear Saved message', () => {
cy.contains('button', 'Create New').should('be.visible');
cy.contains('button', 'Create New').click();
const randomNumber = getRandomInt(1000);
// 將整數轉換為四位數字串,並補零
const fourDigitString = randomNumber.toString().padStart(4, '0');
it('Create a new account with admin role; should show saved message.', () => {
cy.contains('button', 'Create New').should('be.visible').click();
// 將 'unit-test-' 和生成的四位數字串組合
const inputValue = `unit-test-${fourDigitString}`;
cy.get('#input_account_field').type('unit-test-0001');
cy.get('#input_name_field').type('unit-test-0001');
cy.get('#input_first_pwd').type('aaaaaa');
cy.get('.checkbox-and-text').first().find('div').first().click();
// 在 id 為 input_account_field 的 input 元素內填入值
cy.get('#input_account_field').type(inputValue);
cy.get('#input_name_field').type(inputValue);
cy.get('#input_first_pwd').type('aaaaaa');
cy.get('#input_second_pwd').type('aaaaaa');
cy.get('.checkbox-and-text').first().find('div').first().click();
// 確保 Confirm 按鈕存在並可點擊
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
cy.contains('Account added').should('be.visible'); //表示帳號創建成功
});
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
cy.wait('@postUser');
cy.contains('Account added').should('be.visible');
});
it('Confirm button is disabled when required fields are empty.', () => {
cy.contains('button', 'Create New').should('be.visible').click();
cy.get('#input_account_field').type('test');
cy.contains('button', 'Confirm').should('be.disabled');
});
});

View File

@@ -1,57 +1,24 @@
describe('Delete an Account', ()=>{
beforeEach(() => {
cy.visit('/account-admin');
const username = Cypress.env('user').username;
const password = Cypress.env('user').password;
cy.visit('/account-admin');
cy.get('input[id="account"]').type(username);
cy.get('input[id="password"]').type(password);
cy.get('button[type="submit"]').click();
});
import { loginWithFixtures } from '../../support/intercept';
it('Delete an account just created, which is named 000000.', () => {
cy.contains('button', 'Create New').should('be.visible');
cy.contains('button', 'Create New').click();
// 在 id 為 input_account_field 的 input 元素內填入值
cy.get('#input_account_field').type('000000');
cy.get('#input_name_field').type('000000');
cy.get('#input_first_pwd').type('aaaaaa');
cy.get('#input_second_pwd').type('aaaaaa');
cy.get('.checkbox-and-text').first().find('div').first().click();
// 確保 Confirm 按鈕存在並可點擊
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
cy.contains('Account added').should('be.visible'); //表示帳號創建成功
describe('Delete an Account', () => {
beforeEach(() => {
loginWithFixtures();
cy.visit('/account-admin');
cy.wait('@getUsers');
});
cy.contains('span', 'Account').should('be.visible'); // 表示畫面轉導向成功,出現清單列表
// 接著,點選排序按鈕,排序將會造成生升冪排序,我們希望 000000 帳號排在第一個
// 找到包含 'Account' 的 span 元素
cy.get('span:contains("Account")')
.closest('th')
.find('span')
.not(':contains("Account")')
.first()
.click(); // 點選下一个兄弟 span 元素
// 等待,以確保頁面已完全渲染
cy.wait(1000);
it('Delete button opens confirmation modal and deletes on confirm.', () => {
cy.get('img.delete-account').first().click();
cy.contains('ARE YOU SURE TO DELETE').should('be.visible');
cy.get('#sure_to_delete_acct_btn').click();
cy.wait('@deleteUser');
cy.contains('Account deleted').should('be.visible');
});
// 確認 000000 帳號是否出現在第一列
cy.get('tr').filter((index, tr) => {
// 遍歷所有的 tr 元素
const td = Cypress.$(tr).find('td').eq(0); // 找到第一個 td 元素
return td.text().trim() === '000000'; // 檢查其文本內容是否為 000000
}).first().should('exist'); // 確認至少有一個符合條件的 tr 存在
cy.get('img.delete-account').first().click();
cy.contains('h1', 'ARE YOU SURE TO DELETE ?').should('be.visible');
cy.contains('button', 'Yes').click();
cy.contains('Account deleted').should('be.visible'); //表示帳號刪除成功
});
it('Cancel button closes the delete confirmation modal.', () => {
cy.get('img.delete-account').first().click();
cy.contains('ARE YOU SURE TO DELETE').should('be.visible');
cy.get('#calcel_delete_acct_btn').click();
cy.contains('ARE YOU SURE TO DELETE').should('not.exist');
});
});

View File

@@ -1,61 +1,27 @@
import { getRandomInt } from '../../../src/utils/jsUtils';
import { loginWithFixtures } from '../../support/intercept';
const TEST_ACCOUNT = '000000';
const MODAL_TITLE_ACCOUNT_EDIT = 'Account Edit';
const MSG_ACCOUNT_EDITED = 'Saved';
const NUM_OF_SCROLLS = 5;
Cypress.Commands.add('manualScrollToBottom', (repeats = 20) => {
for (let i = 0; i < repeats; i++) {
cy.scrollTo('bottom', { duration: 500 });
cy.wait(500);
}
describe('Edit an account', () => {
beforeEach(() => {
loginWithFixtures();
cy.visit('/account-admin');
cy.wait('@getUsers');
});
it('Edit an account; modify name and see saved message.', () => {
cy.get('.btn-edit').first().click();
cy.wait('@getUserDetail');
cy.contains('h1', MODAL_TITLE_ACCOUNT_EDIT).should('exist');
cy.get('#input_name_field').clear().type('Updated Name');
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
cy.wait('@putUser');
cy.contains(MSG_ACCOUNT_EDITED).should('be.visible');
});
});
describe('Edit an account', ()=>{
beforeEach(() => {
cy.visit('/account-admin');
const username = Cypress.env('user').username;
const password = Cypress.env('user').password;
cy.visit('/account-admin');
cy.get('input[id="account"]').type(username);
cy.get('input[id="password"]').type(password);
cy.get('button[type="submit"]').click();
});
it('Edit an account; modify name and see saved message.', () => {
// 為了讓帳號出現,必須不斷往下滾動捲軸
for(let i = 0; i < NUM_OF_SCROLLS; i++) {
cy.get('#acct_mgmt_data_grid').scrollTo('bottom');
cy.wait(500);
}
// 由於可能在畫面上是 hidden ,這邊使用 exist 而不是使用 visible
cy.contains('.account-cell', TEST_ACCOUNT, { timeout: 10000 }).should('be.exist');
// 找到包含 TEST_ACCOUNT 字串的 .account-cell 元素
cy.contains('.account-cell', TEST_ACCOUNT, { timeout: 10000 })
.parents('tr') // 找到 .account-cell 元素的祖先 tr 元素
.find('.btn-edit') // 在該 tr 元素內找到 .btn-edit 按鈕
.should('be.exist') // 驗證該按鈕可見
.click(); // 點擊該按鈕
cy.contains('h1', MODAL_TITLE_ACCOUNT_EDIT).should('be.exist');
const randomNumber = getRandomInt(1000);
// 將整數轉換為四位數字串,並補零
const fourDigitString = randomNumber.toString().padStart(4, '0');
cy.get('#input_name_field').clear().type( TEST_ACCOUNT + '-' + fourDigitString);
cy.get('#input_first_pwd').type('aaaaaa');
cy.get('#input_second_pwd').type('aaaaaa');
cy.contains('button', 'Confirm')
.should('be.visible')
.and('be.enabled')
.click();
cy.contains(MSG_ACCOUNT_EDITED).should('be.visible'); //表示帳號創建成功
});
});