mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -08:00
feat: Add variables e2e tests (no-changelog) (#6027)
* fix: fix n8n-checkbox alignment * fix: use css variables in checkbox inner margin-top * test: update snapshots * feat: add variables e2e tests (no-changelog) * test: update snapshot
This commit is contained in:
parent
9b59f1df9c
commit
723f81bab0
126
cypress/e2e/23-variables.cy.ts
Normal file
126
cypress/e2e/23-variables.cy.ts
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
import { VariablesPage } from '../pages/variables';
|
||||||
|
import { DEFAULT_USER_EMAIL, DEFAULT_USER_PASSWORD } from '../constants';
|
||||||
|
import { randFirstName, randLastName } from '@ngneat/falso';
|
||||||
|
|
||||||
|
const variablesPage = new VariablesPage();
|
||||||
|
|
||||||
|
const email = DEFAULT_USER_EMAIL;
|
||||||
|
const password = DEFAULT_USER_PASSWORD;
|
||||||
|
const firstName = randFirstName();
|
||||||
|
const lastName = randLastName();
|
||||||
|
|
||||||
|
describe('Variables', () => {
|
||||||
|
before(() => {
|
||||||
|
cy.resetAll();
|
||||||
|
cy.setup({ email, firstName, lastName, password });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the unlicensed action box when the feature is disabled', () => {
|
||||||
|
cy.signin({ email, password });
|
||||||
|
cy.visit(variablesPage.url);
|
||||||
|
|
||||||
|
variablesPage.getters.unavailableResourcesList().should('be.visible');
|
||||||
|
variablesPage.getters.resourcesList().should('not.exist');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('licensed', () => {
|
||||||
|
before(() => {
|
||||||
|
cy.enableFeature('feat:variables');
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.signin({ email, password });
|
||||||
|
cy.visit(variablesPage.url);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the licensed action box when the feature is enabled', () => {
|
||||||
|
variablesPage.getters.emptyResourcesList().should('be.visible');
|
||||||
|
variablesPage.getters.createVariableButton().should('be.visible');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a new variable using empty state row', () => {
|
||||||
|
const key = 'ENV_VAR';
|
||||||
|
const value = 'value';
|
||||||
|
|
||||||
|
variablesPage.actions.createVariableFromEmptyState(key, value);
|
||||||
|
variablesPage.getters.variableRow(key).should('contain', value).should('be.visible');
|
||||||
|
variablesPage.getters.variablesRows().should('have.length', 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a new variable using pre-existing state', () => {
|
||||||
|
const key = 'ENV_VAR_NEW';
|
||||||
|
const value = 'value2';
|
||||||
|
|
||||||
|
variablesPage.actions.createVariable(key, value);
|
||||||
|
variablesPage.getters.variableRow(key).should('contain', value).should('be.visible');
|
||||||
|
variablesPage.getters.variablesRows().should('have.length', 2);
|
||||||
|
|
||||||
|
const otherKey = 'ENV_EXAMPLE';
|
||||||
|
const otherValue = 'value3';
|
||||||
|
|
||||||
|
variablesPage.actions.createVariable(otherKey, otherValue);
|
||||||
|
variablesPage.getters
|
||||||
|
.variableRow(otherKey)
|
||||||
|
.should('contain', otherValue)
|
||||||
|
.should('be.visible');
|
||||||
|
variablesPage.getters.variablesRows().should('have.length', 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get validation errors and cancel variable creation', () => {
|
||||||
|
const key = 'ENV_VAR_NEW$';
|
||||||
|
const value = 'value3';
|
||||||
|
|
||||||
|
variablesPage.getters.createVariableButton().click();
|
||||||
|
const editingRow = variablesPage.getters.variablesEditableRows().eq(0);
|
||||||
|
variablesPage.actions.setRowValue(editingRow, 'key', key);
|
||||||
|
variablesPage.actions.setRowValue(editingRow, 'value', value);
|
||||||
|
editingRow.should('contain', 'This field may contain only letters');
|
||||||
|
variablesPage.getters.editableRowSaveButton(editingRow).should('be.disabled');
|
||||||
|
variablesPage.actions.cancelRowEditing(editingRow);
|
||||||
|
|
||||||
|
variablesPage.getters.variablesRows().should('have.length', 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should edit a variable', () => {
|
||||||
|
const key = 'ENV_VAR_NEW';
|
||||||
|
const newValue = 'value4';
|
||||||
|
|
||||||
|
variablesPage.actions.editRow(key);
|
||||||
|
const editingRow = variablesPage.getters.variablesEditableRows().eq(0);
|
||||||
|
variablesPage.actions.setRowValue(editingRow, 'value', newValue);
|
||||||
|
variablesPage.actions.saveRowEditing(editingRow);
|
||||||
|
|
||||||
|
variablesPage.getters.variableRow(key).should('contain', newValue).should('be.visible');
|
||||||
|
variablesPage.getters.variablesRows().should('have.length', 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete a variable', () => {
|
||||||
|
const key = 'TO_DELETE';
|
||||||
|
const value = 'xxx';
|
||||||
|
|
||||||
|
variablesPage.actions.createVariable(key, value);
|
||||||
|
variablesPage.actions.deleteVariable(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should search for a variable', () => {
|
||||||
|
// One Result
|
||||||
|
variablesPage.getters.searchBar().type('NEW');
|
||||||
|
variablesPage.getters.variablesRows().should('have.length', 1);
|
||||||
|
variablesPage.getters.variableRow('NEW').should('contain.text', 'ENV_VAR_NEW');
|
||||||
|
|
||||||
|
// Multiple Results
|
||||||
|
variablesPage.getters.searchBar().clear().type('ENV_VAR');
|
||||||
|
variablesPage.getters.variablesRows().should('have.length', 2);
|
||||||
|
|
||||||
|
// All Results
|
||||||
|
variablesPage.getters.searchBar().clear().type('ENV');
|
||||||
|
variablesPage.getters.variablesRows().should('have.length', 3);
|
||||||
|
|
||||||
|
// No Results
|
||||||
|
variablesPage.getters.searchBar().clear().type('Some non-existent variable');
|
||||||
|
variablesPage.getters.variablesRows().should('not.exist');
|
||||||
|
|
||||||
|
cy.contains('No variables found').should('be.visible');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
71
cypress/pages/variables.ts
Normal file
71
cypress/pages/variables.ts
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import { BasePage } from './base';
|
||||||
|
import Chainable = Cypress.Chainable;
|
||||||
|
|
||||||
|
export class VariablesPage extends BasePage {
|
||||||
|
url = '/variables';
|
||||||
|
getters = {
|
||||||
|
unavailableResourcesList: () => cy.getByTestId('unavailable-resources-list'),
|
||||||
|
emptyResourcesList: () => cy.getByTestId('empty-resources-list'),
|
||||||
|
resourcesList: () => cy.getByTestId('resources-list'),
|
||||||
|
goToUpgrade: () => cy.getByTestId('go-to-upgrade'),
|
||||||
|
actionBox: () => cy.getByTestId('action-box'),
|
||||||
|
emptyResourcesListNewVariableButton: () => this.getters.emptyResourcesList().find('button'),
|
||||||
|
searchBar: () => cy.getByTestId('resources-list-search').find('input'),
|
||||||
|
createVariableButton: () => cy.getByTestId('resources-list-add'),
|
||||||
|
variablesRows: () => cy.getByTestId('variables-row'),
|
||||||
|
variablesEditableRows: () =>
|
||||||
|
cy.getByTestId('variables-row').filter((index, row) => !!row.querySelector('input')),
|
||||||
|
variableRow: (key: string) =>
|
||||||
|
this.getters.variablesRows().contains(key).parents('[data-test-id="variables-row"]'),
|
||||||
|
editableRowCancelButton: (row: Chainable<JQuery<HTMLElement>>) =>
|
||||||
|
row.getByTestId('variable-row-cancel-button'),
|
||||||
|
editableRowSaveButton: (row: Chainable<JQuery<HTMLElement>>) =>
|
||||||
|
row.getByTestId('variable-row-save-button'),
|
||||||
|
};
|
||||||
|
|
||||||
|
actions = {
|
||||||
|
createVariable: (key: string, value: string) => {
|
||||||
|
this.getters.createVariableButton().click();
|
||||||
|
|
||||||
|
const editingRow = this.getters.variablesEditableRows().eq(0);
|
||||||
|
this.actions.setRowValue(editingRow, 'key', key);
|
||||||
|
this.actions.setRowValue(editingRow, 'value', value);
|
||||||
|
this.actions.saveRowEditing(editingRow);
|
||||||
|
},
|
||||||
|
deleteVariable: (key: string) => {
|
||||||
|
const row = this.getters.variableRow(key);
|
||||||
|
row.within(() => {
|
||||||
|
cy.getByTestId('variable-row-delete-button').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
const modal = cy.get('[role="dialog"]');
|
||||||
|
modal.should('be.visible');
|
||||||
|
modal.get('.btn--confirm').click();
|
||||||
|
},
|
||||||
|
createVariableFromEmptyState: (key: string, value: string) => {
|
||||||
|
this.getters.emptyResourcesListNewVariableButton().click();
|
||||||
|
|
||||||
|
const editingRow = this.getters.variablesEditableRows().eq(0);
|
||||||
|
this.actions.setRowValue(editingRow, 'key', key);
|
||||||
|
this.actions.setRowValue(editingRow, 'value', value);
|
||||||
|
this.actions.saveRowEditing(editingRow);
|
||||||
|
},
|
||||||
|
editRow: (key: string) => {
|
||||||
|
const row = this.getters.variableRow(key);
|
||||||
|
row.within(() => {
|
||||||
|
cy.getByTestId('variable-row-edit-button').click();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setRowValue: (row: Chainable<JQuery<HTMLElement>>, field: 'key' | 'value', value: string) => {
|
||||||
|
row.within(() => {
|
||||||
|
cy.getByTestId(`variable-row-${field}-input`).type('{selectAll}{del}').type(value);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
cancelRowEditing: (row: Chainable<JQuery<HTMLElement>>) => {
|
||||||
|
this.getters.editableRowCancelButton(row).click();
|
||||||
|
},
|
||||||
|
saveRowEditing: (row: Chainable<JQuery<HTMLElement>>) => {
|
||||||
|
this.getters.editableRowSaveButton(row).click();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -130,7 +130,7 @@ function focusFirstInput() {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<tr :class="$style.variablesRow">
|
<tr :class="$style.variablesRow" data-test-id="variables-row">
|
||||||
<td class="variables-key-column">
|
<td class="variables-key-column">
|
||||||
<div>
|
<div>
|
||||||
<span v-if="!editing">{{ data.key }}</span>
|
<span v-if="!editing">{{ data.key }}</span>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Vitest Snapshot v1
|
// Vitest Snapshot v1
|
||||||
|
|
||||||
exports[`VariablesRow > should render correctly 1`] = `
|
exports[`VariablesRow > should render correctly 1`] = `
|
||||||
"<tr class=\\"variablesRow\\">
|
"<tr data-test-id=\\"variables-row\\" class=\\"variablesRow\\">
|
||||||
<td class=\\"variables-key-column\\">
|
<td class=\\"variables-key-column\\">
|
||||||
<div><span>key</span></div>
|
<div><span>key</span></div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -29,7 +29,7 @@ exports[`VariablesRow > should render correctly 1`] = `
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`VariablesRow > should show key and value inputs in edit mode 1`] = `
|
exports[`VariablesRow > should show key and value inputs in edit mode 1`] = `
|
||||||
"<tr class=\\"variablesRow\\">
|
"<tr data-test-id=\\"variables-row\\" class=\\"variablesRow\\">
|
||||||
<td class=\\"variables-key-column\\">
|
<td class=\\"variables-key-column\\">
|
||||||
<div>
|
<div>
|
||||||
<div class=\\"container\\" data-test-id=\\"variable-row-key-input\\">
|
<div class=\\"container\\" data-test-id=\\"variable-row-key-input\\">
|
||||||
|
|
|
@ -259,7 +259,7 @@ function displayName(resource: EnvironmentVariable) {
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!isFeatureEnabled" #empty>
|
<template v-if="!isFeatureEnabled" #empty>
|
||||||
<n8n-action-box
|
<n8n-action-box
|
||||||
data-test-id="empty-resources-list"
|
data-test-id="unavailable-resources-list"
|
||||||
emoji="👋"
|
emoji="👋"
|
||||||
:heading="$locale.baseText(contextBasedTranslationKeys.variables.unavailable.title)"
|
:heading="$locale.baseText(contextBasedTranslationKeys.variables.unavailable.title)"
|
||||||
:description="
|
:description="
|
||||||
|
|
Loading…
Reference in a new issue