2023-11-30 04:09:12 -08:00
|
|
|
import {
|
|
|
|
clickUseWorkflowButtonByTitle,
|
|
|
|
visitTemplateCollectionPage,
|
|
|
|
testData,
|
|
|
|
} from '../pages/template-collection';
|
2023-12-11 10:21:10 -08:00
|
|
|
import * as templateCredentialsSetupPage from '../pages/template-credential-setup';
|
2023-11-27 07:18:10 -08:00
|
|
|
import { WorkflowPage } from '../pages/workflow';
|
2024-01-08 01:35:18 -08:00
|
|
|
import * as formStep from '../composables/setup-template-form-step';
|
|
|
|
import { getSetupWorkflowCredentialsButton } from '../composables/setup-workflow-credentials-button';
|
|
|
|
import * as setupCredsModal from '../composables/modals/workflow-credential-setup-modal';
|
2023-11-27 07:18:10 -08:00
|
|
|
|
|
|
|
const workflowPage = new WorkflowPage();
|
|
|
|
|
|
|
|
const testTemplate = templateCredentialsSetupPage.testData.simpleTemplate;
|
|
|
|
|
2024-01-08 06:34:28 -08:00
|
|
|
// NodeView uses beforeunload listener that will show a browser
|
|
|
|
// native popup, which will block cypress from continuing / exiting.
|
|
|
|
// This prevent the registration of the listener.
|
|
|
|
Cypress.on('window:before:load', (win) => {
|
|
|
|
const origAddEventListener = win.addEventListener;
|
|
|
|
win.addEventListener = (eventName: string, listener: any, opts: any) => {
|
|
|
|
if (eventName === 'beforeunload') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return origAddEventListener.call(win, eventName, listener, opts);
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2023-11-27 07:18:10 -08:00
|
|
|
describe('Template credentials setup', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
cy.intercept('GET', `https://api.n8n.io/api/templates/workflows/${testTemplate.id}`, {
|
|
|
|
fixture: testTemplate.fixture,
|
|
|
|
});
|
2024-02-09 04:47:43 -08:00
|
|
|
cy.intercept('GET', '**/rest/settings', (req) => {
|
|
|
|
// Disable cache
|
|
|
|
delete req.headers['if-none-match']
|
|
|
|
req.reply((res) => {
|
|
|
|
if (res.body.data) {
|
|
|
|
// Disable custom templates host if it has been overridden by another intercept
|
|
|
|
res.body.data.templates = { enabled: true, host: 'https://api.n8n.io/api/' };
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}).as('settingsRequest');
|
2023-11-30 04:09:12 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
it('can be opened from template collection page', () => {
|
|
|
|
visitTemplateCollectionPage(testData.ecommerceStarterPack);
|
2023-12-11 10:21:10 -08:00
|
|
|
templateCredentialsSetupPage.enableTemplateCredentialSetupFeatureFlag();
|
2023-11-30 04:09:12 -08:00
|
|
|
clickUseWorkflowButtonByTitle('Promote new Shopify products on Twitter and Telegram');
|
|
|
|
|
|
|
|
templateCredentialsSetupPage.getters
|
2024-01-09 08:32:42 -08:00
|
|
|
.title(`Set up 'Promote new Shopify products on Twitter and Telegram' template`)
|
2023-11-27 07:18:10 -08:00
|
|
|
.should('be.visible');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('has all the elements on page', () => {
|
2023-12-11 10:21:10 -08:00
|
|
|
templateCredentialsSetupPage.visitTemplateCredentialSetupPage(testTemplate.id);
|
2023-11-27 07:18:10 -08:00
|
|
|
|
|
|
|
templateCredentialsSetupPage.getters
|
2024-01-09 08:32:42 -08:00
|
|
|
.title(`Set up 'Promote new Shopify products on Twitter and Telegram' template`)
|
2023-11-27 07:18:10 -08:00
|
|
|
.should('be.visible');
|
|
|
|
|
|
|
|
templateCredentialsSetupPage.getters
|
|
|
|
.infoCallout()
|
|
|
|
.should(
|
|
|
|
'contain.text',
|
|
|
|
'You need 1x Shopify, 1x X (Formerly Twitter) and 1x Telegram account to setup this template',
|
|
|
|
);
|
|
|
|
|
|
|
|
const expectedAppNames = ['1. Shopify', '2. X (Formerly Twitter)', '3. Telegram'];
|
|
|
|
const expectedAppDescriptions = [
|
|
|
|
'The credential you select will be used in the product created node of the workflow template.',
|
|
|
|
'The credential you select will be used in the Twitter node of the workflow template.',
|
|
|
|
'The credential you select will be used in the Telegram node of the workflow template.',
|
|
|
|
];
|
|
|
|
|
2024-01-08 01:35:18 -08:00
|
|
|
formStep.getFormStep().each(($el, index) => {
|
|
|
|
formStep.getStepHeading($el).should('have.text', expectedAppNames[index]);
|
|
|
|
formStep.getStepDescription($el).should('have.text', expectedAppDescriptions[index]);
|
2023-11-27 07:18:10 -08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('can skip template creation', () => {
|
2023-12-11 10:21:10 -08:00
|
|
|
templateCredentialsSetupPage.visitTemplateCredentialSetupPage(testTemplate.id);
|
2023-11-27 07:18:10 -08:00
|
|
|
|
|
|
|
templateCredentialsSetupPage.getters.skipLink().click();
|
|
|
|
workflowPage.getters.canvasNodes().should('have.length', 3);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('can create credentials and workflow from the template', () => {
|
2023-12-11 10:21:10 -08:00
|
|
|
templateCredentialsSetupPage.visitTemplateCredentialSetupPage(testTemplate.id);
|
2023-11-27 07:18:10 -08:00
|
|
|
|
2023-12-07 09:35:34 -08:00
|
|
|
// Continue button should be disabled if no credentials are created
|
|
|
|
templateCredentialsSetupPage.getters.continueButton().should('be.disabled');
|
2023-11-27 07:18:10 -08:00
|
|
|
|
2024-01-04 00:21:36 -08:00
|
|
|
templateCredentialsSetupPage.fillInDummyCredentialsForApp('Shopify');
|
2023-11-27 07:18:10 -08:00
|
|
|
|
2023-12-07 09:35:34 -08:00
|
|
|
// Continue button should be enabled if at least one has been created
|
|
|
|
templateCredentialsSetupPage.getters.continueButton().should('be.enabled');
|
|
|
|
|
2024-01-04 00:21:36 -08:00
|
|
|
templateCredentialsSetupPage.fillInDummyCredentialsForAppWithConfirm('X (Formerly Twitter)');
|
|
|
|
templateCredentialsSetupPage.fillInDummyCredentialsForApp('Telegram');
|
2023-11-27 07:18:10 -08:00
|
|
|
|
2024-01-08 01:35:18 -08:00
|
|
|
templateCredentialsSetupPage.finishCredentialSetup();
|
2024-01-04 00:21:36 -08:00
|
|
|
|
|
|
|
workflowPage.getters.canvasNodes().should('have.length', 3);
|
2024-01-05 00:36:59 -08:00
|
|
|
|
|
|
|
// Focus the canvas so the copy to clipboard works
|
|
|
|
workflowPage.getters.canvasNodes().eq(0).realClick();
|
|
|
|
workflowPage.actions.selectAll();
|
|
|
|
workflowPage.actions.hitCopy();
|
|
|
|
|
|
|
|
cy.grantBrowserPermissions('clipboardReadWrite', 'clipboardSanitizedWrite');
|
|
|
|
// Check workflow JSON by copying it to clipboard
|
|
|
|
cy.readClipboard().then((workflowJSON) => {
|
|
|
|
const workflow = JSON.parse(workflowJSON);
|
|
|
|
|
|
|
|
expect(workflow.meta).to.haveOwnProperty('templateId', testTemplate.id.toString());
|
|
|
|
workflow.nodes.forEach((node: any) => {
|
|
|
|
expect(Object.keys(node.credentials ?? {})).to.have.lengthOf(1);
|
|
|
|
});
|
|
|
|
});
|
2024-01-04 00:21:36 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should work with a template that has no credentials (ADO-1603)', () => {
|
|
|
|
const templateWithoutCreds = templateCredentialsSetupPage.testData.templateWithoutCredentials;
|
|
|
|
cy.intercept('GET', `https://api.n8n.io/api/templates/workflows/${templateWithoutCreds.id}`, {
|
|
|
|
fixture: templateWithoutCreds.fixture,
|
|
|
|
});
|
|
|
|
templateCredentialsSetupPage.visitTemplateCredentialSetupPage(templateWithoutCreds.id);
|
|
|
|
|
|
|
|
const expectedAppNames = ['1. Email (IMAP)', '2. Nextcloud'];
|
|
|
|
const expectedAppDescriptions = [
|
|
|
|
'The credential you select will be used in the IMAP Email node of the workflow template.',
|
|
|
|
'The credential you select will be used in the Nextcloud node of the workflow template.',
|
|
|
|
];
|
|
|
|
|
2024-01-08 01:35:18 -08:00
|
|
|
formStep.getFormStep().each(($el, index) => {
|
|
|
|
formStep.getStepHeading($el).should('have.text', expectedAppNames[index]);
|
|
|
|
formStep.getStepDescription($el).should('have.text', expectedAppDescriptions[index]);
|
2024-01-04 00:21:36 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
templateCredentialsSetupPage.getters.continueButton().should('be.disabled');
|
|
|
|
|
|
|
|
templateCredentialsSetupPage.fillInDummyCredentialsForApp('Email (IMAP)');
|
|
|
|
templateCredentialsSetupPage.fillInDummyCredentialsForApp('Nextcloud');
|
2023-11-27 07:18:10 -08:00
|
|
|
|
2024-01-08 01:35:18 -08:00
|
|
|
templateCredentialsSetupPage.finishCredentialSetup();
|
2023-11-27 07:18:10 -08:00
|
|
|
|
|
|
|
workflowPage.getters.canvasNodes().should('have.length', 3);
|
|
|
|
});
|
2024-01-08 01:35:18 -08:00
|
|
|
|
|
|
|
describe('Credential setup from workflow editor', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
cy.resetDatabase();
|
|
|
|
cy.signinAsOwner();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should allow credential setup from workflow editor if user skips it during template setup', () => {
|
|
|
|
templateCredentialsSetupPage.visitTemplateCredentialSetupPage(testTemplate.id);
|
|
|
|
templateCredentialsSetupPage.getters.skipLink().click();
|
|
|
|
|
|
|
|
getSetupWorkflowCredentialsButton().should('be.visible');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should allow credential setup from workflow editor if user fills in credentials partially during template setup', () => {
|
|
|
|
templateCredentialsSetupPage.visitTemplateCredentialSetupPage(testTemplate.id);
|
|
|
|
templateCredentialsSetupPage.fillInDummyCredentialsForApp('Shopify');
|
|
|
|
|
|
|
|
templateCredentialsSetupPage.finishCredentialSetup();
|
|
|
|
|
|
|
|
getSetupWorkflowCredentialsButton().should('be.visible');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should fill credentials from workflow editor', () => {
|
|
|
|
templateCredentialsSetupPage.visitTemplateCredentialSetupPage(testTemplate.id);
|
|
|
|
templateCredentialsSetupPage.getters.skipLink().click();
|
|
|
|
|
|
|
|
getSetupWorkflowCredentialsButton().click();
|
|
|
|
setupCredsModal.getWorkflowCredentialsModal().should('be.visible');
|
|
|
|
|
|
|
|
templateCredentialsSetupPage.fillInDummyCredentialsForApp('Shopify');
|
|
|
|
templateCredentialsSetupPage.fillInDummyCredentialsForAppWithConfirm('X (Formerly Twitter)');
|
|
|
|
templateCredentialsSetupPage.fillInDummyCredentialsForApp('Telegram');
|
|
|
|
|
2024-01-09 08:32:42 -08:00
|
|
|
setupCredsModal.closeModalFromContinueButton();
|
|
|
|
setupCredsModal.getWorkflowCredentialsModal().should('not.exist');
|
2024-01-08 01:35:18 -08:00
|
|
|
|
|
|
|
// Focus the canvas so the copy to clipboard works
|
|
|
|
workflowPage.getters.canvasNodes().eq(0).realClick();
|
|
|
|
workflowPage.actions.selectAll();
|
|
|
|
workflowPage.actions.hitCopy();
|
|
|
|
|
|
|
|
cy.grantBrowserPermissions('clipboardReadWrite', 'clipboardSanitizedWrite');
|
|
|
|
// Check workflow JSON by copying it to clipboard
|
|
|
|
cy.readClipboard().then((workflowJSON) => {
|
|
|
|
const workflow = JSON.parse(workflowJSON);
|
|
|
|
|
|
|
|
workflow.nodes.forEach((node: any) => {
|
|
|
|
expect(Object.keys(node.credentials ?? {})).to.have.lengthOf(1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2024-01-08 03:59:04 -08:00
|
|
|
getSetupWorkflowCredentialsButton().should('not.exist');
|
2024-01-08 01:35:18 -08:00
|
|
|
});
|
|
|
|
});
|
2023-11-27 07:18:10 -08:00
|
|
|
});
|