diff --git a/console/.prettierignore b/console/.prettierignore index 975be754e6..c33426ba90 100644 --- a/console/.prettierignore +++ b/console/.prettierignore @@ -2,3 +2,6 @@ # grpc output /src/app/proto + +# dev environment +src/assets/environment.json diff --git a/e2e/.prettierignore b/e2e/.prettierignore new file mode 100644 index 0000000000..d1eeddfaa3 --- /dev/null +++ b/e2e/.prettierignore @@ -0,0 +1,9 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules + +# results +cypress/screenshots/ +cypress/videos/ +cypress/results/ diff --git a/e2e/.prettierrc.json b/e2e/.prettierrc.json new file mode 100644 index 0000000000..7a2a5d19e3 --- /dev/null +++ b/e2e/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "printWidth": 125, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/e2e/cypress/e2e/applications/applications.cy.ts b/e2e/cypress/e2e/applications/applications.cy.ts index 200de99f5a..83cb7c3d67 100644 --- a/e2e/cypress/e2e/applications/applications.cy.ts +++ b/e2e/cypress/e2e/applications/applications.cy.ts @@ -1,31 +1,22 @@ -import { - Apps, - ensureProjectExists, - ensureProjectResourceDoesntExist, -} from "../../support/api/projects"; -import { apiAuth } from "../../support/api/apiauth"; +import { Apps, ensureProjectExists, ensureProjectResourceDoesntExist } from '../../support/api/projects'; +import { apiAuth } from '../../support/api/apiauth'; -describe("applications", () => { - const testProjectName = "e2eprojectapplication"; - const testAppName = "e2eappundertest"; +describe('applications', () => { + const testProjectName = 'e2eprojectapplication'; + const testAppName = 'e2eappundertest'; beforeEach(`ensure it doesn't exist already`, () => { apiAuth().then((api) => { ensureProjectExists(api, testProjectName).then((projectID) => { - ensureProjectResourceDoesntExist( - api, - projectID, - Apps, - testAppName - ).then(() => { + ensureProjectResourceDoesntExist(api, projectID, Apps, testAppName).then(() => { cy.visit(`/projects/${projectID}`); }); }); }); }); - it("add app", () => { - cy.get('[data-e2e="app-card-add"]').should("be.visible").click(); + it('add app', () => { + cy.get('[data-e2e="app-card-add"]').should('be.visible').click(); // select webapp cy.get('[formcontrolname="name"]').type(testAppName); cy.get('[for="WEB"]').click(); @@ -34,17 +25,17 @@ describe("applications", () => { cy.get('[for="PKCE"]').click(); cy.get('[data-e2e="continue-button-authmethod"]').click(); //enter URL - cy.get("cnsl-redirect-uris").eq(0).type("https://testurl.org"); - cy.get("cnsl-redirect-uris").eq(1).type("https://testlogouturl.org"); + cy.get('cnsl-redirect-uris').eq(0).type('https://testurl.org'); + cy.get('cnsl-redirect-uris').eq(1).type('https://testlogouturl.org'); cy.get('[data-e2e="continue-button-redirecturis"]').click(); cy.get('[data-e2e="create-button"]') .click() .then(() => { - cy.get("[id*=overlay]").should("exist"); + cy.get('[id*=overlay]').should('exist'); }); - cy.get(".data-e2e-success"); + cy.get('.data-e2e-success'); cy.wait(200); - cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); + cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist'); //TODO: check client ID/Secret }); }); diff --git a/e2e/cypress/e2e/humans/humans.cy.ts b/e2e/cypress/e2e/humans/humans.cy.ts index 478ff201df..112ae3f990 100644 --- a/e2e/cypress/e2e/humans/humans.cy.ts +++ b/e2e/cypress/e2e/humans/humans.cy.ts @@ -1,50 +1,39 @@ -import { apiAuth } from "../../support/api/apiauth"; -import { - ensureHumanUserExists, - ensureUserDoesntExist, -} from "../../support/api/users"; -import { loginname } from "../../support/login/users"; +import { apiAuth } from '../../support/api/apiauth'; +import { ensureHumanUserExists, ensureUserDoesntExist } from '../../support/api/users'; +import { loginname } from '../../support/login/users'; -describe("humans", () => { +describe('humans', () => { const humansPath = `/users?type=human`; - const testHumanUserNameAdd = "e2ehumanusernameadd"; - const testHumanUserNameRemove = "e2ehumanusernameremove"; + const testHumanUserNameAdd = 'e2ehumanusernameadd'; + const testHumanUserNameRemove = 'e2ehumanusernameremove'; - describe("add", () => { + describe('add', () => { before(`ensure it doesn't exist already`, () => { apiAuth().then((apiCallProperties) => { - ensureUserDoesntExist(apiCallProperties, testHumanUserNameAdd).then( - () => { - cy.visit(humansPath); - } - ); + ensureUserDoesntExist(apiCallProperties, testHumanUserNameAdd).then(() => { + cy.visit(humansPath); + }); }); }); - it("should add a user", () => { - cy.get('[data-e2e="create-user-button"]') - .click(); - cy.url().should("contain", "users/create"); - cy.get('[formcontrolname="email"]') - .type(loginname("e2ehuman", Cypress.env("ORGANIZATION"))); + it('should add a user', () => { + cy.get('[data-e2e="create-user-button"]').click(); + cy.url().should('contain', 'users/create'); + cy.get('[formcontrolname="email"]').type(loginname('e2ehuman', Cypress.env('ORGANIZATION'))); //force needed due to the prefilled username prefix - cy.get('[formcontrolname="userName"]') - .type(testHumanUserNameAdd); - cy.get('[formcontrolname="firstName"]') - .type("e2ehumanfirstname"); - cy.get('[formcontrolname="lastName"]') - .type("e2ehumanlastname"); - cy.get('[formcontrolname="phone"]') - .type("+41 123456789"); + cy.get('[formcontrolname="userName"]').type(testHumanUserNameAdd); + cy.get('[formcontrolname="firstName"]').type('e2ehumanfirstname'); + cy.get('[formcontrolname="lastName"]').type('e2ehumanlastname'); + cy.get('[formcontrolname="phone"]').type('+41 123456789'); cy.get('[data-e2e="create-button"]').click(); - cy.get(".data-e2e-success"); + cy.get('.data-e2e-success'); cy.wait(200); - cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); + cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist'); }); }); - describe("remove", () => { - before("ensure it exists", () => { + describe('remove', () => { + before('ensure it exists', () => { apiAuth().then((api) => { ensureHumanUserExists(api, testHumanUserNameRemove).then(() => { cy.visit(humansPath); @@ -52,19 +41,19 @@ describe("humans", () => { }); }); - it("should delete a human user", () => { - cy.contains("tr", testHumanUserNameRemove) + it('should delete a human user', () => { + cy.contains('tr', testHumanUserNameRemove) // doesn't work, need to force click. // .trigger('mouseover') .find('[data-e2e="enabled-delete-button"]') - .click({force: true}); + .click({ force: true }); cy.get('[data-e2e="confirm-dialog-input"]') .focus() - .type(loginname(testHumanUserNameRemove, Cypress.env("ORGANIZATION"))); + .type(loginname(testHumanUserNameRemove, Cypress.env('ORGANIZATION'))); cy.get('[data-e2e="confirm-dialog-button"]').click(); - cy.get(".data-e2e-success"); + cy.get('.data-e2e-success'); cy.wait(200); - cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); + cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist'); }); }); }); diff --git a/e2e/cypress/e2e/machines/machines.cy.ts b/e2e/cypress/e2e/machines/machines.cy.ts index 2ea052f138..b9181e9c39 100644 --- a/e2e/cypress/e2e/machines/machines.cy.ts +++ b/e2e/cypress/e2e/machines/machines.cy.ts @@ -1,46 +1,37 @@ -import { apiAuth } from "../../support/api/apiauth"; -import { - ensureMachineUserExists, - ensureUserDoesntExist, -} from "../../support/api/users"; -import { loginname } from "../../support/login/users"; +import { apiAuth } from '../../support/api/apiauth'; +import { ensureMachineUserExists, ensureUserDoesntExist } from '../../support/api/users'; +import { loginname } from '../../support/login/users'; -describe("machines", () => { +describe('machines', () => { const machinesPath = `/users?type=machine`; - const testMachineUserNameAdd = "e2emachineusernameadd"; - const testMachineUserNameRemove = "e2emachineusernameremove"; + const testMachineUserNameAdd = 'e2emachineusernameadd'; + const testMachineUserNameRemove = 'e2emachineusernameremove'; - describe("add", () => { + describe('add', () => { before(`ensure it doesn't exist already`, () => { apiAuth().then((apiCallProperties) => { - ensureUserDoesntExist(apiCallProperties, testMachineUserNameAdd).then( - () => { - cy.visit(machinesPath); - } - ); + ensureUserDoesntExist(apiCallProperties, testMachineUserNameAdd).then(() => { + cy.visit(machinesPath); + }); }); }); - it("should add a machine", () => { - cy.get('[data-e2e="create-user-button"]') - .click(); - cy.url().should("contain", "users/create-machine"); + it('should add a machine', () => { + cy.get('[data-e2e="create-user-button"]').click(); + cy.url().should('contain', 'users/create-machine'); //force needed due to the prefilled username prefix - cy.get('[formcontrolname="userName"]') - .type(testMachineUserNameAdd); - cy.get('[formcontrolname="name"]') - .type("e2emachinename"); - cy.get('[formcontrolname="description"]') - .type("e2emachinedescription"); + cy.get('[formcontrolname="userName"]').type(testMachineUserNameAdd); + cy.get('[formcontrolname="name"]').type('e2emachinename'); + cy.get('[formcontrolname="description"]').type('e2emachinedescription'); cy.get('[data-e2e="create-button"]').click(); - cy.get(".data-e2e-success"); + cy.get('.data-e2e-success'); cy.wait(200); - cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); + cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist'); }); }); - describe("remove", () => { - before("ensure it exists", () => { + describe('remove', () => { + before('ensure it exists', () => { apiAuth().then((api) => { ensureMachineUserExists(api, testMachineUserNameRemove).then(() => { cy.visit(machinesPath); @@ -48,19 +39,19 @@ describe("machines", () => { }); }); - it("should delete a machine", () => { - cy.contains("tr", testMachineUserNameRemove) + it('should delete a machine', () => { + cy.contains('tr', testMachineUserNameRemove) // doesn't work, need to force click. // .trigger('mouseover') .find('[data-e2e="enabled-delete-button"]') - .click({force: true}); + .click({ force: true }); cy.get('[data-e2e="confirm-dialog-input"]') .focus() - .type(loginname(testMachineUserNameRemove, Cypress.env("ORGANIZATION"))); + .type(loginname(testMachineUserNameRemove, Cypress.env('ORGANIZATION'))); cy.get('[data-e2e="confirm-dialog-button"]').click(); - cy.get(".data-e2e-success"); + cy.get('.data-e2e-success'); cy.wait(200); - cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); + cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist'); }); }); }); diff --git a/e2e/cypress/e2e/permissions/permissions.cy.ts b/e2e/cypress/e2e/permissions/permissions.cy.ts index 17a97f375a..bb072daedb 100644 --- a/e2e/cypress/e2e/permissions/permissions.cy.ts +++ b/e2e/cypress/e2e/permissions/permissions.cy.ts @@ -1,49 +1,44 @@ -import { apiAuth } from "../../support/api/apiauth"; -import { ensureProjectExists, ensureProjectResourceDoesntExist, Roles } from "../../support/api/projects"; +import { apiAuth } from '../../support/api/apiauth'; +import { ensureProjectExists, ensureProjectResourceDoesntExist, Roles } from '../../support/api/projects'; describe('permissions', () => { + const testProjectName = 'e2eprojectpermission'; + const testAppName = 'e2eapppermission'; + const testRoleName = 'e2eroleundertestname'; + const testRoleDisplay = 'e2eroleundertestdisplay'; + const testRoleGroup = 'e2eroleundertestgroup'; + const testGrantName = 'e2egrantundertest'; - const testProjectName = 'e2eprojectpermission' - const testAppName = 'e2eapppermission' - const testRoleName = 'e2eroleundertestname' - const testRoleDisplay = 'e2eroleundertestdisplay' - const testRoleGroup = 'e2eroleundertestgroup' - const testGrantName = 'e2egrantundertest' + var projectId: number; - var projectId: number + beforeEach(() => { + apiAuth().then((apiCalls) => { + ensureProjectExists(apiCalls, testProjectName).then((projId) => { + projectId = projId; + }); + }); + }); + describe('add role', () => { beforeEach(() => { - apiAuth().then(apiCalls => { - ensureProjectExists(apiCalls, testProjectName).then(projId => { - projectId = projId - }) - }) - }) + apiAuth().then((api) => { + ensureProjectResourceDoesntExist(api, projectId, Roles, testRoleName); + cy.visit(`/projects/${projectId}?id=roles`); + }); + }); - describe('add role', () => { - beforeEach(()=> { - apiAuth().then((api)=> { - ensureProjectResourceDoesntExist(api, projectId, Roles, testRoleName) - cy.visit(`/projects/${projectId}?id=roles`) - }) - }) - - it('should add a role', () => { - cy.get('[data-e2e="add-new-role"]').click() - cy.get('[formcontrolname="key"]') - .type(testRoleName) - cy.get('[formcontrolname="displayName"]') - .type(testRoleDisplay) - cy.get('[formcontrolname="group"]') - .type(testRoleGroup) - cy.get('[data-e2e="save-button"]') - .click() - cy.get('.data-e2e-success') - cy.wait(200) - cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist') - }) - }) -}) + it('should add a role', () => { + cy.get('[data-e2e="add-new-role"]').click(); + cy.get('[formcontrolname="key"]').type(testRoleName); + cy.get('[formcontrolname="displayName"]').type(testRoleDisplay); + cy.get('[formcontrolname="group"]').type(testRoleGroup); + cy.get('[data-e2e="save-button"]').click(); + cy.get('.data-e2e-success'); + cy.wait(200); + cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist'); + }); + }); +}); /* describe('permissions', () => { @@ -112,4 +107,4 @@ describe('permissions', () => { }) }) -*/ \ No newline at end of file +*/ diff --git a/e2e/cypress/e2e/projects/projects.cy.ts b/e2e/cypress/e2e/projects/projects.cy.ts index 5a7a8daeb3..04f67ea630 100644 --- a/e2e/cypress/e2e/projects/projects.cy.ts +++ b/e2e/cypress/e2e/projects/projects.cy.ts @@ -1,15 +1,12 @@ -import { apiAuth } from "../../support/api/apiauth"; -import { - ensureProjectDoesntExist, - ensureProjectExists, -} from "../../support/api/projects"; +import { apiAuth } from '../../support/api/apiauth'; +import { ensureProjectDoesntExist, ensureProjectExists } from '../../support/api/projects'; -describe("projects", () => { - const testProjectNameCreate = "e2eprojectcreate"; - const testProjectNameDeleteList = "e2eprojectdeletelist"; - const testProjectNameDeleteGrid = "e2eprojectdeletegrid"; +describe('projects', () => { + const testProjectNameCreate = 'e2eprojectcreate'; + const testProjectNameDeleteList = 'e2eprojectdeletelist'; + const testProjectNameDeleteGrid = 'e2eprojectdeletegrid'; - describe("add project", () => { + describe('add project', () => { beforeEach(`ensure it doesn't exist already`, () => { apiAuth().then((api) => { ensureProjectDoesntExist(api, testProjectNameCreate); @@ -17,60 +14,56 @@ describe("projects", () => { cy.visit(`/projects`); }); - it("should add a project", () => { - cy.get(".add-project-button").click({ force: true }); - cy.get("input").type(testProjectNameCreate); + it('should add a project', () => { + cy.get('.add-project-button').click({ force: true }); + cy.get('input').type(testProjectNameCreate); cy.get('[data-e2e="continue-button"]').click(); - cy.get(".data-e2e-success"); + cy.get('.data-e2e-success'); cy.wait(200); - cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); + cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist'); }); }); - describe("remove project", () => { - describe("list view", () => { - beforeEach("ensure it exists", () => { + describe('remove project', () => { + describe('list view', () => { + beforeEach('ensure it exists', () => { apiAuth().then((api) => { ensureProjectExists(api, testProjectNameDeleteList); }); cy.visit(`/projects`); }); - it("removes the project", () => { + it('removes the project', () => { cy.get('[data-e2e="toggle-grid"]').click(); cy.get('[data-e2e="timestamp"]'); - cy.contains("tr", testProjectNameDeleteList, { timeout: 1000 }) + cy.contains('tr', testProjectNameDeleteList, { timeout: 1000 }) .find('[data-e2e="delete-project-button"]') .click({ force: true }); - cy.get('[data-e2e="confirm-dialog-input"]') - .focus() - .type(testProjectNameDeleteList); + cy.get('[data-e2e="confirm-dialog-input"]').focus().type(testProjectNameDeleteList); cy.get('[data-e2e="confirm-dialog-button"]').click(); - cy.get(".data-e2e-success"); + cy.get('.data-e2e-success'); cy.wait(200); - cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); + cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist'); }); }); - describe("grid view", () => { - beforeEach("ensure it exists", () => { + describe('grid view', () => { + beforeEach('ensure it exists', () => { apiAuth().then((api) => { ensureProjectExists(api, testProjectNameDeleteGrid); }); cy.visit(`/projects`); }); - it("removes the project", () => { + it('removes the project', () => { cy.contains('[data-e2e="grid-card"]', testProjectNameDeleteGrid) .find('[data-e2e="delete-project-button"]') - .click({force: true}); - cy.get('[data-e2e="confirm-dialog-input"]') - .focus() - .type(testProjectNameDeleteGrid); + .click({ force: true }); + cy.get('[data-e2e="confirm-dialog-input"]').focus().type(testProjectNameDeleteGrid); cy.get('[data-e2e="confirm-dialog-button"]').click(); - cy.get(".data-e2e-success"); + cy.get('.data-e2e-success'); cy.wait(200); - cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); + cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist'); }); }); }); diff --git a/e2e/cypress/e2e/settings/login-policy.cy.ts b/e2e/cypress/e2e/settings/login-policy.cy.ts index f2cc38c44f..291de7c9ee 100644 --- a/e2e/cypress/e2e/settings/login-policy.cy.ts +++ b/e2e/cypress/e2e/settings/login-policy.cy.ts @@ -1,45 +1,38 @@ -import { apiAuth } from "../../support/api/apiauth"; -import { ensureHumanUserExists } from "../../support/api/users"; -import { login, User } from "../../support/login/users"; +import { apiAuth } from '../../support/api/apiauth'; +import { ensureHumanUserExists } from '../../support/api/users'; +import { login, User } from '../../support/login/users'; -describe("login policy", ()=> { +describe('login policy', () => { + const orgPath = `/org`; - const orgPath = `/org` - - ;[User.OrgOwner].forEach(user => { - - describe(`as user "${user}"`, () => { - - beforeEach(()=> { - login(user) - cy.visit(orgPath) - // TODO: Why force? - cy.contains('[data-e2e="policy-card"]', 'Login Policy').contains('button', 'Modify').click({force: true}) // TODO: select data-e2e - apiAuth().then(api => { - ensureHumanUserExists(api, User.LoginPolicyUser) - }) - }) - - // TODO: verify email - - it.skip(`username and password disallowed`, () => { - login(User.LoginPolicyUser, "123abcABC?&*") - }) - it(`registering is allowed`) - it(`registering is disallowed`) - it(`login by an external IDP is allowed`) - it(`login by an external IDP is disallowed`) - it(`MFA is forced`) - it(`MFA is not forced`) - it(`the password reset option is hidden`) - it(`the password reset option is shown`) - it(`passwordless login is allowed`) - it(`passwordless login is disallowed`) - describe('identity providers', () => { - - }) - }) - }) -}) + [User.OrgOwner].forEach((user) => { + describe(`as user "${user}"`, () => { + beforeEach(() => { + login(user); + cy.visit(orgPath); + // TODO: Why force? + cy.contains('[data-e2e="policy-card"]', 'Login Policy').contains('button', 'Modify').click({ force: true }); // TODO: select data-e2e + apiAuth().then((api) => { + ensureHumanUserExists(api, User.LoginPolicyUser); + }); + }); + // TODO: verify email + it.skip(`username and password disallowed`, () => { + login(User.LoginPolicyUser, '123abcABC?&*'); + }); + it(`registering is allowed`); + it(`registering is disallowed`); + it(`login by an external IDP is allowed`); + it(`login by an external IDP is disallowed`); + it(`MFA is forced`); + it(`MFA is not forced`); + it(`the password reset option is hidden`); + it(`the password reset option is shown`); + it(`passwordless login is allowed`); + it(`passwordless login is disallowed`); + describe('identity providers', () => {}); + }); + }); +}); diff --git a/e2e/cypress/e2e/settings/password-complexity.cy.ts b/e2e/cypress/e2e/settings/password-complexity.cy.ts index 148d6c0b41..19027d0935 100644 --- a/e2e/cypress/e2e/settings/password-complexity.cy.ts +++ b/e2e/cypress/e2e/settings/password-complexity.cy.ts @@ -1,34 +1,29 @@ -import { login, User } from "../../support/login/users"; +import { login, User } from '../../support/login/users'; -describe("password complexity", ()=> { +describe('password complexity', () => { + const orgPath = `/org`; + const testProjectName = 'e2eproject'; - const orgPath = `/org` - const testProjectName = 'e2eproject' - - ;[User.OrgOwner].forEach(user => { - - describe(`as user "${user}"`, () => { - - beforeEach(()=> { - login(user) - cy.visit(orgPath) - // TODO: Why force? - cy.contains('[data-e2e="policy-card"]', 'Password Complexity').contains('button', 'Modify').click({force: true}) // TODO: select data-e2e - }) - - // TODO: fix saving password complexity policy bug - - it(`should restrict passwords that don't have the minimal length`) - it(`should require passwords to contain a number if option is switched on`) - it(`should not require passwords to contain a number if option is switched off`) - it(`should require passwords to contain a symbol if option is switched on`) - it(`should not require passwords to contain a symbol if option is switched off`) - it(`should require passwords to contain a lowercase letter if option is switched on`) - it(`should not require passwords to contain a lowercase letter if option is switched off`) - it(`should require passwords to contain an uppercase letter if option is switched on`) - it(`should not require passwords to contain an uppercase letter if option is switched off`) - }) - }) -}) + [User.OrgOwner].forEach((user) => { + describe(`as user "${user}"`, () => { + beforeEach(() => { + login(user); + cy.visit(orgPath); + // TODO: Why force? + cy.contains('[data-e2e="policy-card"]', 'Password Complexity').contains('button', 'Modify').click({ force: true }); // TODO: select data-e2e + }); + // TODO: fix saving password complexity policy bug + it(`should restrict passwords that don't have the minimal length`); + it(`should require passwords to contain a number if option is switched on`); + it(`should not require passwords to contain a number if option is switched off`); + it(`should require passwords to contain a symbol if option is switched on`); + it(`should not require passwords to contain a symbol if option is switched off`); + it(`should require passwords to contain a lowercase letter if option is switched on`); + it(`should not require passwords to contain a lowercase letter if option is switched off`); + it(`should require passwords to contain an uppercase letter if option is switched on`); + it(`should not require passwords to contain an uppercase letter if option is switched off`); + }); + }); +}); diff --git a/e2e/cypress/support/api/apiauth.ts b/e2e/cypress/support/api/apiauth.ts index ad493be847..3256fbc217 100644 --- a/e2e/cypress/support/api/apiauth.ts +++ b/e2e/cypress/support/api/apiauth.ts @@ -1,15 +1,15 @@ -import { login, User } from 'support/login/users' +import { login, User } from 'support/login/users'; export interface apiCallProperties { - authHeader: string - mgntBaseURL: string + authHeader: string; + mgntBaseURL: string; } export function apiAuth(): Cypress.Chainable { - return login(User.IAMAdminUser, 'Password1!', false, true).then(token => { - return { - authHeader: `Bearer ${token}`, - mgntBaseURL: `${Cypress.env("BACKEND_URL")}/management/v1/`, - } - }) + return login(User.IAMAdminUser, 'Password1!', false, true).then((token) => { + return { + authHeader: `Bearer ${token}`, + mgntBaseURL: `${Cypress.env('BACKEND_URL')}/management/v1/`, + }; + }); } diff --git a/e2e/cypress/support/api/ensure.ts b/e2e/cypress/support/api/ensure.ts index b08df296a7..a41fae0aa2 100644 --- a/e2e/cypress/support/api/ensure.ts +++ b/e2e/cypress/support/api/ensure.ts @@ -1,89 +1,118 @@ -import { apiCallProperties } from "./apiauth" +import { apiCallProperties } from './apiauth'; -export function ensureSomethingExists(api: apiCallProperties, searchPath: string, find: (entity: any) => boolean, createPath: string, body: any): Cypress.Chainable { - - return searchSomething(api, searchPath, find).then(sRes => { - if (sRes.entity) { - return cy.wrap({ - id: sRes.entity.id, - initialSequence: 0 - }) - } - return cy.request({ - method: 'POST', - url: `${api.mgntBaseURL}${createPath}`, - headers: { - Authorization: api.authHeader - }, - body: body, - failOnStatusCode: false, - followRedirect: false, - }).then(cRes => { - expect(cRes.status).to.equal(200) - return { - id: cRes.body.id, - initialSequence: sRes.sequence - } +export function ensureSomethingExists( + api: apiCallProperties, + searchPath: string, + find: (entity: any) => boolean, + createPath: string, + body: any, +): Cypress.Chainable { + return searchSomething(api, searchPath, find) + .then((sRes) => { + if (sRes.entity) { + return cy.wrap({ + id: sRes.entity.id, + initialSequence: 0, + }); + } + return cy + .request({ + method: 'POST', + url: `${api.mgntBaseURL}${createPath}`, + headers: { + Authorization: api.authHeader, + }, + body: body, + failOnStatusCode: false, + followRedirect: false, }) - }).then((data) => { - awaitDesired(90, (entity) => !!entity, data.initialSequence, api, searchPath, find) - return cy.wrap(data.id) + .then((cRes) => { + expect(cRes.status).to.equal(200); + return { + id: cRes.body.id, + initialSequence: sRes.sequence, + }; + }); }) + .then((data) => { + awaitDesired(90, (entity) => !!entity, data.initialSequence, api, searchPath, find); + return cy.wrap(data.id); + }); } -export function ensureSomethingDoesntExist(api: apiCallProperties, searchPath: string, find: (entity: any) => boolean, deletePath: (entity: any) => string): Cypress.Chainable { - - return searchSomething(api, searchPath, find).then(sRes => { - if (!sRes.entity) { - return cy.wrap(0) - } - return cy.request({ - method: 'DELETE', - url: `${api.mgntBaseURL}${deletePath(sRes.entity)}`, - headers: { - Authorization: api.authHeader - }, - failOnStatusCode: false - }).then((dRes) => { - expect(dRes.status).to.equal(200) - return sRes.sequence +export function ensureSomethingDoesntExist( + api: apiCallProperties, + searchPath: string, + find: (entity: any) => boolean, + deletePath: (entity: any) => string, +): Cypress.Chainable { + return searchSomething(api, searchPath, find) + .then((sRes) => { + if (!sRes.entity) { + return cy.wrap(0); + } + return cy + .request({ + method: 'DELETE', + url: `${api.mgntBaseURL}${deletePath(sRes.entity)}`, + headers: { + Authorization: api.authHeader, + }, + failOnStatusCode: false, }) - }).then((initialSequence) => { - awaitDesired(90, (entity) => !entity , initialSequence, api, searchPath, find) - return null + .then((dRes) => { + expect(dRes.status).to.equal(200); + return sRes.sequence; + }); }) + .then((initialSequence) => { + awaitDesired(90, (entity) => !entity, initialSequence, api, searchPath, find); + return null; + }); } type SearchResult = { - entity: any - sequence: number -} + entity: any; + sequence: number; +}; -function searchSomething(api: apiCallProperties, searchPath: string, find: (entity: any) => boolean): Cypress.Chainable { - - return cy.request({ - method: 'POST', - url: `${api.mgntBaseURL}${searchPath}`, - headers: { - Authorization: api.authHeader - }, - }).then(res => { - return { - entity: res.body.result?.find(find) || null, - sequence: res.body.details.processedSequence - } +function searchSomething( + api: apiCallProperties, + searchPath: string, + find: (entity: any) => boolean, +): Cypress.Chainable { + return cy + .request({ + method: 'POST', + url: `${api.mgntBaseURL}${searchPath}`, + headers: { + Authorization: api.authHeader, + }, }) + .then((res) => { + return { + entity: res.body.result?.find(find) || null, + sequence: res.body.details.processedSequence, + }; + }); } -function awaitDesired(trials: number, expectEntity: (entity: any) => boolean, initialSequence: number, api: apiCallProperties, searchPath: string, find: (entity: any) => boolean) { - searchSomething(api, searchPath, find).then(resp => { - const foundExpectedEntity = expectEntity(resp.entity) - const foundExpectedSequence = resp.sequence > initialSequence +function awaitDesired( + trials: number, + expectEntity: (entity: any) => boolean, + initialSequence: number, + api: apiCallProperties, + searchPath: string, + find: (entity: any) => boolean, +) { + searchSomething(api, searchPath, find).then((resp) => { + const foundExpectedEntity = expectEntity(resp.entity); + const foundExpectedSequence = resp.sequence > initialSequence; - if (!foundExpectedEntity || !foundExpectedSequence) { - expect(trials, `trying ${trials} more times`).to.be.greaterThan(0); - cy.wait(1000) - awaitDesired(trials - 1, expectEntity, initialSequence, api, searchPath, find) - } - }) + if (!foundExpectedEntity || !foundExpectedSequence) { + expect(trials, `trying ${trials} more times`).to.be.greaterThan(0); + cy.wait(1000); + awaitDesired(trials - 1, expectEntity, initialSequence, api, searchPath, find); + } + }); } diff --git a/e2e/cypress/support/api/policies.ts b/e2e/cypress/support/api/policies.ts index 477e595bce..cc6fa32dcb 100644 --- a/e2e/cypress/support/api/policies.ts +++ b/e2e/cypress/support/api/policies.ts @@ -1,19 +1,18 @@ -import { apiCallProperties } from "./apiauth" - +import { apiCallProperties } from './apiauth'; export enum Policy { - Label = "label" + Label = 'label', } export function resetPolicy(api: apiCallProperties, policy: Policy) { - cy.request({ - method: 'DELETE', - url: `${api.mgntBaseURL}/policies/${policy}`, - headers: { - Authorization: api.authHeader - }, - }).then(res => { - expect(res.status).to.equal(200) - return null - }) -} \ No newline at end of file + cy.request({ + method: 'DELETE', + url: `${api.mgntBaseURL}/policies/${policy}`, + headers: { + Authorization: api.authHeader, + }, + }).then((res) => { + expect(res.status).to.equal(200); + return null; + }); +} diff --git a/e2e/cypress/support/api/projects.ts b/e2e/cypress/support/api/projects.ts index caa7a083b4..cc6f931405 100644 --- a/e2e/cypress/support/api/projects.ts +++ b/e2e/cypress/support/api/projects.ts @@ -1,80 +1,69 @@ -import { apiCallProperties } from "./apiauth" -import { ensureSomethingDoesntExist, ensureSomethingExists } from "./ensure" +import { apiCallProperties } from './apiauth'; +import { ensureSomethingDoesntExist, ensureSomethingExists } from './ensure'; export function ensureProjectExists(api: apiCallProperties, projectName: string): Cypress.Chainable { - - return ensureSomethingExists( - api, - `projects/_search`, - (project: any) => project.name === projectName, - 'projects', - { name: projectName }, - ) + return ensureSomethingExists(api, `projects/_search`, (project: any) => project.name === projectName, 'projects', { + name: projectName, + }); } export function ensureProjectDoesntExist(api: apiCallProperties, projectName: string): Cypress.Chainable { - - return ensureSomethingDoesntExist( - api, - `projects/_search`, - (project: any) => project.name === projectName, - (project) => `projects/${project.id}`, - ) + return ensureSomethingDoesntExist( + api, + `projects/_search`, + (project: any) => project.name === projectName, + (project) => `projects/${project.id}`, + ); } class ResourceType { - constructor( - public resourcePath: string, - public compareProperty: string, - public identifierProperty: string, - ){} + constructor(public resourcePath: string, public compareProperty: string, public identifierProperty: string) {} } -export const Apps = new ResourceType('apps', 'name', 'id') -export const Roles = new ResourceType('roles', 'key', 'key') +export const Apps = new ResourceType('apps', 'name', 'id'); +export const Roles = new ResourceType('roles', 'key', 'key'); //export const Grants = new ResourceType('apps', 'name') - -export function ensureProjectResourceDoesntExist(api: apiCallProperties, projectId: number, resourceType: ResourceType, resourceName: string): Cypress.Chainable { - return ensureSomethingDoesntExist( - api, - `projects/${projectId}/${resourceType.resourcePath}/_search`, - (resource: any) => { - return resource[resourceType.compareProperty] === resourceName - }, - (resource) => { - return `projects/${projectId}/${resourceType.resourcePath}/${resource[resourceType.identifierProperty]}` - } - ) +export function ensureProjectResourceDoesntExist( + api: apiCallProperties, + projectId: number, + resourceType: ResourceType, + resourceName: string, +): Cypress.Chainable { + return ensureSomethingDoesntExist( + api, + `projects/${projectId}/${resourceType.resourcePath}/_search`, + (resource: any) => { + return resource[resourceType.compareProperty] === resourceName; + }, + (resource) => { + return `projects/${projectId}/${resourceType.resourcePath}/${resource[resourceType.identifierProperty]}`; + }, + ); } -export function ensureApplicationExists(api: apiCallProperties, projectId: number, appName: string): Cypress.Chainable { - - return ensureSomethingExists( - api, - `projects/${projectId}/${Apps.resourcePath}/_search`, - (resource: any) => resource.name === appName, - `projects/${projectId}/${Apps.resourcePath}/oidc`, - { - name: appName, - redirectUris: [ - 'https://e2eredirecturl.org' - ], - responseTypes: [ - "OIDC_RESPONSE_TYPE_CODE" - ], - grantTypes: [ - "OIDC_GRANT_TYPE_AUTHORIZATION_CODE" - ], - authMethodType: "OIDC_AUTH_METHOD_TYPE_NONE", - postLogoutRedirectUris: [ - 'https://e2elogoutredirecturl.org' - ], -/* "clientId": "129383004379407963@e2eprojectpermission", +export function ensureApplicationExists( + api: apiCallProperties, + projectId: number, + appName: string, +): Cypress.Chainable { + return ensureSomethingExists( + api, + `projects/${projectId}/${Apps.resourcePath}/_search`, + (resource: any) => resource.name === appName, + `projects/${projectId}/${Apps.resourcePath}/oidc`, + { + name: appName, + redirectUris: ['https://e2eredirecturl.org'], + responseTypes: ['OIDC_RESPONSE_TYPE_CODE'], + grantTypes: ['OIDC_GRANT_TYPE_AUTHORIZATION_CODE'], + authMethodType: 'OIDC_AUTH_METHOD_TYPE_NONE', + postLogoutRedirectUris: ['https://e2elogoutredirecturl.org'], + /* "clientId": "129383004379407963@e2eprojectpermission", "clockSkew": "0s", "allowedOrigins": [ "https://testurl.org" ]*/ - }, - ) + }, + ); } diff --git a/e2e/cypress/support/api/users.ts b/e2e/cypress/support/api/users.ts index ae9ea301f9..8795ee567c 100644 --- a/e2e/cypress/support/api/users.ts +++ b/e2e/cypress/support/api/users.ts @@ -1,49 +1,35 @@ -import { apiCallProperties } from "./apiauth" -import { ensureSomethingDoesntExist, ensureSomethingExists } from "./ensure" +import { apiCallProperties } from './apiauth'; +import { ensureSomethingDoesntExist, ensureSomethingExists } from './ensure'; export function ensureHumanUserExists(api: apiCallProperties, username: string): Cypress.Chainable { - - return ensureSomethingExists( - api, - 'users/_search', - (user: any) => user.userName === username, - 'users/human', - { - user_name: username, - profile: { - first_name: 'e2efirstName', - last_name: 'e2elastName', - }, - email: { - email: 'e2e@email.ch', - }, - phone: { - phone: '+41 123456789', - }, - }) + return ensureSomethingExists(api, 'users/_search', (user: any) => user.userName === username, 'users/human', { + user_name: username, + profile: { + first_name: 'e2efirstName', + last_name: 'e2elastName', + }, + email: { + email: 'e2e@email.ch', + }, + phone: { + phone: '+41 123456789', + }, + }); } export function ensureMachineUserExists(api: apiCallProperties, username: string): Cypress.Chainable { - - return ensureSomethingExists( - api, - 'users/_search', - (user: any) => user.userName === username, - 'users/machine', - { - user_name: username, - name: 'e2emachinename', - description: 'e2emachinedescription', - }, - ) + return ensureSomethingExists(api, 'users/_search', (user: any) => user.userName === username, 'users/machine', { + user_name: username, + name: 'e2emachinename', + description: 'e2emachinedescription', + }); } export function ensureUserDoesntExist(api: apiCallProperties, username: string): Cypress.Chainable { - - return ensureSomethingDoesntExist( - api, - 'users/_search', - (user: any) => user.userName === username, - (user) => `users/${user.id}` - ) + return ensureSomethingDoesntExist( + api, + 'users/_search', + (user: any) => user.userName === username, + (user) => `users/${user.id}`, + ); } diff --git a/e2e/cypress/support/commands.ts b/e2e/cypress/support/commands.ts index 241a1fe176..2b296c489a 100644 --- a/e2e/cypress/support/commands.ts +++ b/e2e/cypress/support/commands.ts @@ -2,11 +2,11 @@ namespace Cypress { interface Chainable { */ - /** - * Custom command that authenticates a user. - * - * @example cy.consolelogin('hodor', 'hodor1234') - */ +/** + * Custom command that authenticates a user. + * + * @example cy.consolelogin('hodor', 'hodor1234') + */ /* consolelogin(username: string, password: string): void } } @@ -23,4 +23,4 @@ Cypress.Commands.add('consolelogin', { prevSubject: false }, (username: string, cy.location('pathname', {timeout: 5 * 1000}).should('eq', '/'); }) }) -*/ \ No newline at end of file +*/ diff --git a/e2e/cypress/support/e2e.ts b/e2e/cypress/support/e2e.ts index f80f74f8e1..598ab5f0d7 100644 --- a/e2e/cypress/support/e2e.ts +++ b/e2e/cypress/support/e2e.ts @@ -14,7 +14,7 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import './commands' +import './commands'; // Alternatively you can use CommonJS syntax: -// require('./commands') \ No newline at end of file +// require('./commands') diff --git a/e2e/cypress/support/index.ts b/e2e/cypress/support/index.ts index 8953ca08c7..d2356297ca 100644 --- a/e2e/cypress/support/index.ts +++ b/e2e/cypress/support/index.ts @@ -1,12 +1,10 @@ -require('cypress-terminal-report/src/installLogsCollector')(); +require('cypress-terminal-report/src/installLogsCollector')(); /** * @type {Cypress.PluginConfig} */ module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config -} +}; //import './commands' - diff --git a/e2e/cypress/support/login/users.ts b/e2e/cypress/support/login/users.ts index ad2acd029d..fbad9d534a 100644 --- a/e2e/cypress/support/login/users.ts +++ b/e2e/cypress/support/login/users.ts @@ -1,4 +1,4 @@ -import { debug } from "console"; +import { debug } from 'console'; export enum User { OrgOwner = 'org_owner', @@ -23,77 +23,85 @@ export function login( const loginUrl: string = '/ui/login'; const issuerUrl: string = '/oauth/v2'; - return cy.session( - creds.username, - () => { - const cookies = new Map(); + return cy + .session( + creds.username, + () => { + const cookies = new Map(); - cy.intercept({ - times: 6 - }, req => { - req.headers['cookie'] = requestCookies(cookies); - req.continue((res) => { - updateCookies(res.headers['set-cookie'] as string[], cookies); - }); - }) + cy.intercept( + { + times: 6, + }, + (req) => { + req.headers['cookie'] = requestCookies(cookies); + req.continue((res) => { + updateCookies(res.headers['set-cookie'] as string[], cookies); + }); + }, + ); - let userToken: string - cy.intercept({ - method: 'POST', - url: `${issuerUrl}/token`, - }, req => { - req.continue(res => { - userToken = res.body["access_token"]} - ) - }).as('token') + let userToken: string; + cy.intercept( + { + method: 'POST', + url: `${issuerUrl}/token`, + }, + (req) => { + req.continue((res) => { + userToken = res.body['access_token']; + }); + }, + ).as('token'); - cy.intercept({ + cy.intercept({ method: 'POST', url: `${loginUrl}/password*`, times: 1, - }).as('password'); + }).as('password'); - cy.visit(loginUrl, { retryOnNetworkFailure: true }); + cy.visit(loginUrl, { retryOnNetworkFailure: true }); - onUsernameScreen ? onUsernameScreen() : null; - cy.get('#loginName').type(creds.username); - cy.get('#submit-button').click(); + onUsernameScreen ? onUsernameScreen() : null; + cy.get('#loginName').type(creds.username); + cy.get('#submit-button').click(); - onPasswordScreen ? onPasswordScreen() : null; - cy.get('#password').type(creds.password); - cy.get('#submit-button').click(); + onPasswordScreen ? onPasswordScreen() : null; + cy.get('#password').type(creds.password); + cy.get('#submit-button').click(); - cy.wait('@password').then((interception) => { - if (interception.response.body.indexOf('Multifactor Setup') === -1){ - return - } + cy.wait('@password').then((interception) => { + if (interception.response.body.indexOf('Multifactor Setup') === -1) { + return; + } - cy.contains('button', 'skip').click() - cy.get('#change-old-password').type(creds.password) - cy.get('#change-new-password').type(creds.password) - cy.get('#change-password-confirmation').type(creds.password) - cy.contains('button', 'next').click() - cy.contains('button', 'next').click() - }) + cy.contains('button', 'skip').click(); + cy.get('#change-old-password').type(creds.password); + cy.get('#change-new-password').type(creds.password); + cy.get('#change-password-confirmation').type(creds.password); + cy.contains('button', 'next').click(); + cy.contains('button', 'next').click(); + }); - cy.wait('@token').then(() => { - cy.task('safetoken', {key: creds.username, token: userToken}) - }) + cy.wait('@token').then(() => { + cy.task('safetoken', { key: creds.username, token: userToken }); + }); - onAuthenticated ? onAuthenticated() : null; + onAuthenticated ? onAuthenticated() : null; - cy.get("[data-e2e=authenticated-welcome]"); - }, - { - validate: () => { - if (force) { - throw new Error('clear session'); - } + cy.get('[data-e2e=authenticated-welcome]'); }, - }, - ).then(() => { - return cy.task('loadtoken', {key: creds.username}) - }); + { + validate: () => { + if (force) { + throw new Error('clear session'); + } + }, + }, + ) + .then(() => { + return cy.task('loadtoken', { key: creds.username }); + }); } export function loginname(withoutDomain: string, org?: string): string { @@ -101,10 +109,9 @@ export function loginname(withoutDomain: string, org?: string): string { } function credentials(user: User, pw?: string) { - // TODO: ugly - const woDomain = user == User.IAMAdminUser ? User.IAMAdminUser : `${user}_user_name` - const org = Cypress.env('ORGANIZATION') ? Cypress.env('ORGANIZATION') : 'zitadel' + const woDomain = user == User.IAMAdminUser ? User.IAMAdminUser : `${user}_user_name`; + const org = Cypress.env('ORGANIZATION') ? Cypress.env('ORGANIZATION') : 'zitadel'; return { username: loginname(woDomain, org), diff --git a/e2e/docker-compose.yaml b/e2e/docker-compose.yaml index 86fd98fd06..2ceb740373 100644 --- a/e2e/docker-compose.yaml +++ b/e2e/docker-compose.yaml @@ -22,7 +22,7 @@ services: image: 'cockroachdb/cockroach:v22.1.0' command: 'start-single-node --insecure --http-addr :9090' healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9090/health?ready=1"] + test: ['CMD', 'curl', '-f', 'http://localhost:9090/health?ready=1'] interval: '10s' timeout: '30s' retries: 5 @@ -36,10 +36,11 @@ services: prepare: image: node:18-alpine3.15 working_dir: /e2e - user: "$UID" + user: '$UID' volumes: - - .:/e2e - command: "npm ci --omit=dev && npx run wait-on http://localhost:8080" + - .:/e2e + command: 'sh -c "npm ci --omit=dev && npm run lint && npx wait-on http://localhost:8080/debug/ready"' + network_mode: host e2e: image: cypress/included:10.3.0 @@ -51,9 +52,9 @@ services: prepare: condition: 'service_completed_successfully' working_dir: /e2e - user: "$UID" + user: '$UID' volumes: - - .:/e2e + - .:/e2e network_mode: host networks: diff --git a/e2e/package-lock.json b/e2e/package-lock.json index b46065436d..824c58bb20 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -11,7 +11,8 @@ "debug": "^4.3.4", "jsonwebtoken": "^8.5.1", "mochawesome": "^7.1.3", - "typescript": "^4.7.4", + "prettier": "^2.7.1", + "typescript": "^4.8.3", "wait-on": "^6.0.1" }, "devDependencies": { @@ -2125,6 +2126,20 @@ "node": ">=0.10.0" } }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -2544,9 +2559,9 @@ } }, "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4327,6 +4342,11 @@ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true }, + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==" + }, "pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -4643,9 +4663,9 @@ "dev": true }, "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==" }, "universalify": { "version": "2.0.0", diff --git a/e2e/package.json b/e2e/package.json index 1dd66d56de..44a263367d 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -5,15 +5,18 @@ "open": "npx cypress open", "e2e": "npx cypress run", "open:dev": "CYPRESS_BASE_URL=http://localhost:4200 CYPRESS_BACKEND_URL=http://localhost:8080 npm run open", - "e2e:dev": "CYPRESS_BASE_URL=http://localhost:4200 CYPRESS_BACKEND_URL=http://localhost:8080 npm run e2e" + "e2e:dev": "CYPRESS_BASE_URL=http://localhost:4200 CYPRESS_BACKEND_URL=http://localhost:8080 npm run e2e", + "lint": "prettier --check cypress", + "lint:fix": "prettier --write cypress" }, "private": true, "dependencies": { "debug": "^4.3.4", "jsonwebtoken": "^8.5.1", "mochawesome": "^7.1.3", - "typescript": "^4.7.4", - "wait-on": "^6.0.1" + "wait-on": "^6.0.1", + "typescript": "^4.8.3", + "prettier": "^2.7.1" }, "devDependencies": { "@types/node": "^18.7.13",