n8n/cypress/e2e/29-templates.cy.ts
Ricardo Espinoza 4277e92ec0
feat(editor): Add new /templates/search endpoint (#8227)
Updating n8n front-end to use the new search endpoint powered by TypeSense.

Endpoint is deployed on staging API so, in order to test it, use this env var:
```export N8N_TEMPLATES_HOST=https://api-staging.n8n.io/api```

**NOTE**: This PR should not be merged until [backend changes](https://github.com/n8n-io/creators-site/pull/118) are merged and released.

## Related tickets and issues
https://linear.app/n8n/issue/ADO-1555/update-in-app-search-to-work-with-the-new-back-end


## Review / Merge checklist
- [x] PR title and summary are descriptive. **Remember, the title automatically goes into the changelog. Use `(no-changelog)` otherwise.** ([conventions](https://github.com/n8n-io/n8n/blob/master/.github/pull_request_title_conventions.md))
- [ ] Tests included.
   > A bug is not considered fixed, unless a test is added to prevent it from happening again.
   > A feature is not complete without tests.
2024-01-15 16:19:24 -05:00

140 lines
5.8 KiB
TypeScript

import { TemplatesPage } from '../pages/templates';
import { WorkflowPage } from '../pages/workflow';
import OnboardingWorkflow from '../fixtures/Onboarding_workflow.json';
import WorkflowTemplate from '../fixtures/Workflow_template_write_http_query.json';
import { TemplateWorkflowPage } from '../pages/template-workflow';
const templatesPage = new TemplatesPage();
const workflowPage = new WorkflowPage();
const templateWorkflowPage = new TemplateWorkflowPage();
describe('Templates', () => {
beforeEach(() => {
cy.intercept('GET', '**/api/templates/search?page=1&rows=20&category=&search=', { fixture: 'templates_search/all_templates_search_response.json' }).as('searchRequest');
cy.intercept('GET', '**/api/templates/search?page=1&rows=20&category=Sales*', { fixture: 'templates_search/sales_templates_search_response.json' }).as('categorySearchRequest');
cy.intercept('GET', '**/api/templates/workflows/*', { fixture: 'templates_search/test_template_preview.json' }).as('singleTemplateRequest');
cy.intercept('GET', '**/api/workflows/templates/*', { fixture: 'templates_search/test_template_import.json' }).as('singleTemplateRequest');
});
it('can open onboarding flow', () => {
templatesPage.actions.openOnboardingFlow(1234, OnboardingWorkflow.name, OnboardingWorkflow);
cy.url().then(($url) => {
expect($url).to.match(/.*\/workflow\/.*?onboardingId=1234$/);
})
workflowPage.actions.shouldHaveWorkflowName(`Demo: ${name}`);
workflowPage.getters.canvasNodes().should('have.length', 4);
workflowPage.getters.stickies().should('have.length', 1);
workflowPage.getters.canvasNodes().first().should('have.descendants', '.node-pin-data-icon');
});
it('can import template', () => {
templatesPage.actions.importTemplate(1234, OnboardingWorkflow.name, OnboardingWorkflow);
cy.url().then(($url) => {
expect($url).to.include('/workflow/new?templateId=1234');
});
workflowPage.getters.canvasNodes().should('have.length', 4);
workflowPage.getters.stickies().should('have.length', 1);
workflowPage.actions.shouldHaveWorkflowName(OnboardingWorkflow.name);
});
it('should save template id with the workflow', () => {
cy.visit(templatesPage.url);
cy.get('.el-skeleton.n8n-loading').should('not.exist');
templatesPage.getters.firstTemplateCard().should('exist');
templatesPage.getters.templatesLoadingContainer().should('not.exist');
templatesPage.getters.firstTemplateCard().click();
cy.url().should('include', '/templates/');
cy.url().then(($url) => {
const templateId = $url.split('/').pop();
templatesPage.getters.useTemplateButton().click();
cy.url().should('include', '/workflow/new');
workflowPage.actions.saveWorkflowOnButtonClick();
workflowPage.actions.selectAll();
workflowPage.actions.hitCopy();
cy.grantBrowserPermissions('clipboardReadWrite', 'clipboardSanitizedWrite');
// Check workflow JSON by copying it to clipboard
cy.readClipboard().then((workflowJSON) => {
expect(workflowJSON).to.contain(`"templateId": "${templateId}"`);
});
});
});
it('can open template with images and hides workflow screenshots', () => {
templateWorkflowPage.actions.openTemplate(WorkflowTemplate);
templateWorkflowPage.getters.description().find('img').should('have.length', 1);
});
it('renders search elements correctly', () => {
cy.visit(templatesPage.url);
templatesPage.getters.searchInput().should('exist');
templatesPage.getters.allCategoriesFilter().should('exist');
templatesPage.getters.categoryFilters().should('have.length.greaterThan', 1);
templatesPage.getters.templateCards().should('have.length.greaterThan', 0);
});
it('can filter templates by category', () => {
cy.visit(templatesPage.url);
templatesPage.getters.templatesLoadingContainer().should('not.exist');
templatesPage.getters.expandCategoriesButton().click();
templatesPage.getters.categoryFilter('sales').should('exist');
let initialTemplateCount = 0;
let initialCollectionCount = 0;
templatesPage.getters.templateCountLabel().then(($el) => {
initialTemplateCount = parseInt($el.text().replace(/\D/g, ''), 10);
templatesPage.getters.collectionCountLabel().then(($el) => {
initialCollectionCount = parseInt($el.text().replace(/\D/g, ''), 10);
templatesPage.getters.categoryFilter('sales').click();
templatesPage.getters.templatesLoadingContainer().should('not.exist');
// Should have less templates and collections after selecting a category
templatesPage.getters.templateCountLabel().should(($el) => {
expect(parseInt($el.text().replace(/\D/g, ''), 10)).to.be.lessThan(initialTemplateCount);
});
templatesPage.getters.collectionCountLabel().should(($el) => {
expect(parseInt($el.text().replace(/\D/g, ''), 10)).to.be.lessThan(initialCollectionCount);
});
});
});
});
it('should preserve search query in URL', () => {
cy.visit(templatesPage.url);
templatesPage.getters.templatesLoadingContainer().should('not.exist');
templatesPage.getters.expandCategoriesButton().click();
templatesPage.getters.categoryFilter('sales').should('exist');
templatesPage.getters.categoryFilter('sales').click();
templatesPage.getters.searchInput().type('auto');
cy.url().should('include', '?categories=');
cy.url().should('include', '&search=');
cy.reload();
// Should preserve search query in URL
cy.url().should('include', '?categories=');
cy.url().should('include', '&search=');
// Sales category should still be selected
templatesPage.getters.categoryFilter('sales').find('label').should('have.class', 'is-checked');
// Search input should still have the search query
templatesPage.getters.searchInput().should('have.value', 'auto');
// Sales checkbox should be pushed to the top
templatesPage.getters.categoryFilters().eq(1).then(($el) => {
expect($el.text()).to.equal('Sales');
});
});
});