Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions cypress/e2e/randomsampling.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
describe('Random Sampling Module', () => {
beforeEach(function () {
// 1. Visit the application frontend
cy.visit('/front/');

// 2. Load credentials and login
cy.fixture('cred').then((cred) => {
this.cred = cred;
cy.get('input[type="text"]').type(this.cred.username);
cy.get('input[type="password"]').type(this.cred.password);
cy.get('button[type="submit"]').click();

// Ensure login is successful and we are on the home page
cy.contains('Welcome').should('be.visible');
});
Comment on lines +7 to +15
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use cy.login defined in commands.js?

});

it('successfully initiates a random sampling of claims', function () {
// 1. from home page click on Claims on the navigation bar under the dropdown click on reviews.
cy.contains('Claims').click();
cy.contains('Reviews').click();

cy.contains(/CLAIM SAMPLE/i).click();

// 3. A popup appears. Enter sample percentage and select a task group from the dropdown.
cy.contains('h2', 'Claim sample').should('be.visible');

const randomPercent = Math.floor(Math.random() * 16) + 5;
cy.enterMuiInput('Percent of claims', randomPercent);
cy.chooseMuiSelect('Task Group', 'any');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this task group guaranteed to exist for our CI setup?


// 4. Finally, click on create sampling. The sampling is complete
cy.contains(/CREATE CLAIM SAMPLE/i).click({ force: true });

// Verify success confirmation and return to page
cy.contains(/New task for claim sampling was created/i).should('be.visible');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the task creation the end of this workflow? Don't we want to check the entities are created as expected after the task is approved?

cy.contains(/CONFIRM/i).click({ force: true });

// Verify that the table is visible again
cy.get('table').should('be.visible');
});
});
158 changes: 95 additions & 63 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ Cypress.Commands.add('deleteModuleConfig', (moduleName) => {

Cypress.Commands.add('shouldHaveMenuItemsInOrder', (expectedMenuNames) => {
cy.get('div[role="button"]')
.filter(':visible')
.should(($buttons) => {
expect($buttons).to.have.length(expectedMenuNames.length);
.filter(':visible')
.should(($buttons) => {
expect($buttons).to.have.length(expectedMenuNames.length);

// Check each sub menu item text and order
expectedMenuNames.forEach((itemText, index) => {
expect($buttons.eq(index)).to.contain(itemText);
// Check each sub menu item text and order
expectedMenuNames.forEach((itemText, index) => {
expect($buttons.eq(index)).to.contain(itemText);
});
});
});
})

Cypress.Commands.add('deleteActivities', (activityNames) => {
Expand Down Expand Up @@ -196,7 +196,7 @@ Cypress.Commands.add('deleteProgram', (programName) => {
cy.wrap(row).within(() => {
// Find and click the Delete button in this row
cy.get('button[title="Delete"]')
.click({force: true});
.click({ force: true });
});

// Confirm deletion in dialog
Expand All @@ -215,7 +215,7 @@ Cypress.Commands.add('deleteProgram', (programName) => {
cy.get('ul.MuiList-root li')
.first()
.should('contain', 'Delete program');
// .should('contain', `Delete program ${programName}`); //TODO: switch to this after fix
// .should('contain', `Delete program ${programName}`); //TODO: switch to this after fix

// Close journal drawer
cy.get('.MuiDrawer-paperAnchorRight button')
Expand Down Expand Up @@ -299,33 +299,33 @@ Cypress.Commands.add(
programName,
maxBeneficiaries,
programType,
institution='',
description='',
institution = '',
description = '',
) => {
cy.assertMuiInput('Code', programCode)
cy.assertMuiInput('Name', programName)
const today = getTodayFormatted()
cy.assertMuiInput('Date from', today)
cy.assertMuiInput('Date to', today)
cy.assertMuiInput('Max Beneficiaries', maxBeneficiaries)
cy.assertMuiInput('Institution', institution)
cy.assertMuiInput('Description', description, 'textarea')
})
cy.assertMuiInput('Code', programCode)
cy.assertMuiInput('Name', programName)
const today = getTodayFormatted()
cy.assertMuiInput('Date from', today)
cy.assertMuiInput('Date to', today)
cy.assertMuiInput('Max Beneficiaries', maxBeneficiaries)
cy.assertMuiInput('Institution', institution)
cy.assertMuiInput('Description', description, 'textarea')
})

Cypress.Commands.add(
'checkProgramFieldValuesInListView',
(programCode, programName, maxBeneficiaries, programType) => {

cy.contains('tfoot', 'Rows Per Page')
cy.contains('td', programName).should('exist')
cy.contains('td', programName)
.parent('tr').within(() => {
cy.contains('td', programCode)
cy.contains('td', programType)
cy.contains('td', maxBeneficiaries)
cy.contains('td', new Date().toISOString().substring(0, 10))
})
})
cy.contains('tfoot', 'Rows Per Page')
cy.contains('td', programName).should('exist')
cy.contains('td', programName)
.parent('tr').within(() => {
cy.contains('td', programCode)
cy.contains('td', programType)
cy.contains('td', maxBeneficiaries)
cy.contains('td', new Date().toISOString().substring(0, 10))
})
})

Cypress.Commands.add('uploadIndividualsCSV', (numIndividuals) => {
cy.task('updateCSV', { numIndividuals }).then(() => {
Expand Down Expand Up @@ -356,7 +356,7 @@ Cypress.Commands.add('ensureSufficientIndividuals', (expectedNumIndividuals) =>
cy.visit('/front/individuals')
cy.uploadIndividualsCSV(numToAdd)

cy.wait(100*numToAdd) // group creation takes time
cy.wait(100 * numToAdd) // group creation takes time

cy.visit('/front/individuals')
cy.getItemCount("Individual").then(newCount => {
Expand All @@ -381,7 +381,7 @@ Cypress.Commands.add('ensureSufficientHouseholds', (expectedNumGroups) => {
cy.visit('/front/individuals')
cy.uploadIndividualsCSV(numIndividualsToAdd)

cy.wait(100*numIndividualsToAdd) // group creation takes time
cy.wait(100 * numIndividualsToAdd) // group creation takes time

cy.visit('/front/groups')
cy.getItemCount("Group").then(newCount => {
Expand Down Expand Up @@ -599,34 +599,66 @@ Cypress.Commands.add('enrollGroupBeneficiariesIntoProgram', (
})


Cypress.Commands.add('enterMuiInput', (label, value, inputTag='input') => {
cy.contains('label', label)
// Custom command to enter text into a Material UI (MUI) input field.
// Uses a regex for the label to be more resilient to exact text matches (e.g. case sensitivity).
Cypress.Commands.add('enterMuiInput', (label, value, inputTag = 'input') => {
cy.contains('label', new RegExp(label))
.siblings('.MuiInputBase-root')
.find(inputTag)
.first()
.clear({force: true})
.type(value, {force: true});
.clear({ force: true })
.type(value, { force: true });
})

// Custom command to choose an option from a Material UI (MUI) select/dropdown.
// Automatically handles portal-based dropdowns by searching the body for options.
Cypress.Commands.add('chooseMuiSelect', (label, value) => {
cy.contains('label', label)
// Find the label using regex and click the associated input/button
cy.contains('label', new RegExp(label))
.siblings('.MuiInputBase-root')
.find('[role="button"]')
.click()
.find('[role="button"], .MuiSelect-select, .MuiInput-input, .MuiInputBase-input')
.click({ force: true })

cy.contains('[role="listbox"] li', value).as('option')
cy.get('@option').click()
// Wait a bit for portal to appear
cy.wait(500);

// Check if options are available in common MUI portal locations
const selector = '[role="listbox"] li, [role="menu"] li, [role="presentation"] li, .MuiMenuItem-root';
cy.get('body').then(($body) => {
if ($body.find(selector).length > 0 && !$body.text().includes('No options')) {
// Find the specific option by text regex
const valRegex = new RegExp(value, 'i');
const $options = $body.find(selector);

let found = false;
$options.each((index, el) => {
if (valRegex.test(el.innerText)) {
cy.wrap(el).click({ force: true });
found = true;
return false; // break
}
});

// Fallback: if specific value not found, pick the first available option
if (!found) {
cy.wrap($options.first()).click({ force: true });
}
} else {
// Fallback: just close the dropdown by clicking the body if no options found
cy.get('body').click(0, 0);
}
Comment on lines +642 to +649
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another PR is going to implement chooseMuiSelectFirstAvailable: https://github.com/openimis/openimis-dist_dkr/pull/84/changes#r2913544525 Consider using that instead of this fallback as the intention is more explicit.

})
})

Cypress.Commands.add('assertMuiInput', (label, value, inputTag='input') => {
Cypress.Commands.add('assertMuiInput', (label, value, inputTag = 'input') => {
cy.contains('label', label)
.siblings('.MuiInputBase-root')
.find(inputTag)
.should('be.visible')
.and('have.value', value);
})

Cypress.Commands.add('assertMuiInputDisabled', (label, value=null, inputTag='input') => {
Cypress.Commands.add('assertMuiInputDisabled', (label, value = null, inputTag = 'input') => {
const input = cy.contains('label', label)
.siblings('.MuiInputBase-root')
.find(inputTag)
Expand All @@ -653,27 +685,27 @@ Cypress.Commands.add('chooseMuiAutocomplete', (label, value) => {
})

Cypress.Commands.add('setModuleConfig', (moduleName, configFixtureFile) => {
cy.deleteModuleConfig(moduleName)

cy.contains('a', 'Module configurations').click()

// Create module config using fixture config file
cy.contains('a', 'Add module configuration').click()
cy.get('input[name="module"]').type(moduleName)
cy.get('select[name="layer"]').select('backend')
cy.get('input[name="version"]').type(1)

cy.fixture(configFixtureFile).then((config) => {
const configString = JSON.stringify(config, null, 2);
cy.get('textarea[name="config"]')
.type(configString, {
parseSpecialCharSequences: false,
delay: 0 // Type faster
});
cy.deleteModuleConfig(moduleName)

cy.contains('a', 'Module configurations').click()

// Create module config using fixture config file
cy.contains('a', 'Add module configuration').click()
cy.get('input[name="module"]').type(moduleName)
cy.get('select[name="layer"]').select('backend')
cy.get('input[name="version"]').type(1)

cy.fixture(configFixtureFile).then((config) => {
const configString = JSON.stringify(config, null, 2);
cy.get('textarea[name="config"]')
.type(configString, {
parseSpecialCharSequences: false,
delay: 0 // Type faster
});

cy.get('input[value="Save"]').click()
cy.contains("was added successfully")
})
cy.get('input[value="Save"]').click()
cy.contains("was added successfully")
})
})

Cypress.Commands.add('getItemCount', (itemName) => {
Expand Down
Loading