chore(e2e): formatting with prettier (#4385)

* prettier in e2e

* format

* typescript as dev dependency

* ci all, check linting

* resolve liniting issues

* fix wait-on

* fix package-lock.json

Co-authored-by: Elio Bischof <eliobischof@gmail.com>
This commit is contained in:
Max Peintner 2022-09-19 19:49:46 +02:00 committed by GitHub
parent 8505eb4cc9
commit fc4f4096e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 522 additions and 526 deletions

View File

@ -2,3 +2,6 @@
# grpc output # grpc output
/src/app/proto /src/app/proto
# dev environment
src/assets/environment.json

9
e2e/.prettierignore Normal file
View File

@ -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/

5
e2e/.prettierrc.json Normal file
View File

@ -0,0 +1,5 @@
{
"printWidth": 125,
"singleQuote": true,
"trailingComma": "all"
}

View File

@ -1,31 +1,22 @@
import { import { Apps, ensureProjectExists, ensureProjectResourceDoesntExist } from '../../support/api/projects';
Apps, import { apiAuth } from '../../support/api/apiauth';
ensureProjectExists,
ensureProjectResourceDoesntExist,
} from "../../support/api/projects";
import { apiAuth } from "../../support/api/apiauth";
describe("applications", () => { describe('applications', () => {
const testProjectName = "e2eprojectapplication"; const testProjectName = 'e2eprojectapplication';
const testAppName = "e2eappundertest"; const testAppName = 'e2eappundertest';
beforeEach(`ensure it doesn't exist already`, () => { beforeEach(`ensure it doesn't exist already`, () => {
apiAuth().then((api) => { apiAuth().then((api) => {
ensureProjectExists(api, testProjectName).then((projectID) => { ensureProjectExists(api, testProjectName).then((projectID) => {
ensureProjectResourceDoesntExist( ensureProjectResourceDoesntExist(api, projectID, Apps, testAppName).then(() => {
api,
projectID,
Apps,
testAppName
).then(() => {
cy.visit(`/projects/${projectID}`); cy.visit(`/projects/${projectID}`);
}); });
}); });
}); });
}); });
it("add app", () => { it('add app', () => {
cy.get('[data-e2e="app-card-add"]').should("be.visible").click(); cy.get('[data-e2e="app-card-add"]').should('be.visible').click();
// select webapp // select webapp
cy.get('[formcontrolname="name"]').type(testAppName); cy.get('[formcontrolname="name"]').type(testAppName);
cy.get('[for="WEB"]').click(); cy.get('[for="WEB"]').click();
@ -34,17 +25,17 @@ describe("applications", () => {
cy.get('[for="PKCE"]').click(); cy.get('[for="PKCE"]').click();
cy.get('[data-e2e="continue-button-authmethod"]').click(); cy.get('[data-e2e="continue-button-authmethod"]').click();
//enter URL //enter URL
cy.get("cnsl-redirect-uris").eq(0).type("https://testurl.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('cnsl-redirect-uris').eq(1).type('https://testlogouturl.org');
cy.get('[data-e2e="continue-button-redirecturis"]').click(); cy.get('[data-e2e="continue-button-redirecturis"]').click();
cy.get('[data-e2e="create-button"]') cy.get('[data-e2e="create-button"]')
.click() .click()
.then(() => { .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.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 //TODO: check client ID/Secret
}); });
}); });

View File

@ -1,50 +1,39 @@
import { apiAuth } from "../../support/api/apiauth"; import { apiAuth } from '../../support/api/apiauth';
import { import { ensureHumanUserExists, ensureUserDoesntExist } from '../../support/api/users';
ensureHumanUserExists, import { loginname } from '../../support/login/users';
ensureUserDoesntExist,
} from "../../support/api/users";
import { loginname } from "../../support/login/users";
describe("humans", () => { describe('humans', () => {
const humansPath = `/users?type=human`; const humansPath = `/users?type=human`;
const testHumanUserNameAdd = "e2ehumanusernameadd"; const testHumanUserNameAdd = 'e2ehumanusernameadd';
const testHumanUserNameRemove = "e2ehumanusernameremove"; const testHumanUserNameRemove = 'e2ehumanusernameremove';
describe("add", () => { describe('add', () => {
before(`ensure it doesn't exist already`, () => { before(`ensure it doesn't exist already`, () => {
apiAuth().then((apiCallProperties) => { apiAuth().then((apiCallProperties) => {
ensureUserDoesntExist(apiCallProperties, testHumanUserNameAdd).then( ensureUserDoesntExist(apiCallProperties, testHumanUserNameAdd).then(() => {
() => { cy.visit(humansPath);
cy.visit(humansPath); });
}
);
}); });
}); });
it("should add a user", () => { it('should add a user', () => {
cy.get('[data-e2e="create-user-button"]') cy.get('[data-e2e="create-user-button"]').click();
.click(); cy.url().should('contain', 'users/create');
cy.url().should("contain", "users/create"); cy.get('[formcontrolname="email"]').type(loginname('e2ehuman', Cypress.env('ORGANIZATION')));
cy.get('[formcontrolname="email"]')
.type(loginname("e2ehuman", Cypress.env("ORGANIZATION")));
//force needed due to the prefilled username prefix //force needed due to the prefilled username prefix
cy.get('[formcontrolname="userName"]') cy.get('[formcontrolname="userName"]').type(testHumanUserNameAdd);
.type(testHumanUserNameAdd); cy.get('[formcontrolname="firstName"]').type('e2ehumanfirstname');
cy.get('[formcontrolname="firstName"]') cy.get('[formcontrolname="lastName"]').type('e2ehumanlastname');
.type("e2ehumanfirstname"); cy.get('[formcontrolname="phone"]').type('+41 123456789');
cy.get('[formcontrolname="lastName"]')
.type("e2ehumanlastname");
cy.get('[formcontrolname="phone"]')
.type("+41 123456789");
cy.get('[data-e2e="create-button"]').click(); cy.get('[data-e2e="create-button"]').click();
cy.get(".data-e2e-success"); cy.get('.data-e2e-success');
cy.wait(200); 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", () => { describe('remove', () => {
before("ensure it exists", () => { before('ensure it exists', () => {
apiAuth().then((api) => { apiAuth().then((api) => {
ensureHumanUserExists(api, testHumanUserNameRemove).then(() => { ensureHumanUserExists(api, testHumanUserNameRemove).then(() => {
cy.visit(humansPath); cy.visit(humansPath);
@ -52,19 +41,19 @@ describe("humans", () => {
}); });
}); });
it("should delete a human user", () => { it('should delete a human user', () => {
cy.contains("tr", testHumanUserNameRemove) cy.contains('tr', testHumanUserNameRemove)
// doesn't work, need to force click. // doesn't work, need to force click.
// .trigger('mouseover') // .trigger('mouseover')
.find('[data-e2e="enabled-delete-button"]') .find('[data-e2e="enabled-delete-button"]')
.click({force: true}); .click({ force: true });
cy.get('[data-e2e="confirm-dialog-input"]') cy.get('[data-e2e="confirm-dialog-input"]')
.focus() .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="confirm-dialog-button"]').click();
cy.get(".data-e2e-success"); cy.get('.data-e2e-success');
cy.wait(200); cy.wait(200);
cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
}); });
}); });
}); });

View File

@ -1,46 +1,37 @@
import { apiAuth } from "../../support/api/apiauth"; import { apiAuth } from '../../support/api/apiauth';
import { import { ensureMachineUserExists, ensureUserDoesntExist } from '../../support/api/users';
ensureMachineUserExists, import { loginname } from '../../support/login/users';
ensureUserDoesntExist,
} from "../../support/api/users";
import { loginname } from "../../support/login/users";
describe("machines", () => { describe('machines', () => {
const machinesPath = `/users?type=machine`; const machinesPath = `/users?type=machine`;
const testMachineUserNameAdd = "e2emachineusernameadd"; const testMachineUserNameAdd = 'e2emachineusernameadd';
const testMachineUserNameRemove = "e2emachineusernameremove"; const testMachineUserNameRemove = 'e2emachineusernameremove';
describe("add", () => { describe('add', () => {
before(`ensure it doesn't exist already`, () => { before(`ensure it doesn't exist already`, () => {
apiAuth().then((apiCallProperties) => { apiAuth().then((apiCallProperties) => {
ensureUserDoesntExist(apiCallProperties, testMachineUserNameAdd).then( ensureUserDoesntExist(apiCallProperties, testMachineUserNameAdd).then(() => {
() => { cy.visit(machinesPath);
cy.visit(machinesPath); });
}
);
}); });
}); });
it("should add a machine", () => { it('should add a machine', () => {
cy.get('[data-e2e="create-user-button"]') cy.get('[data-e2e="create-user-button"]').click();
.click(); cy.url().should('contain', 'users/create-machine');
cy.url().should("contain", "users/create-machine");
//force needed due to the prefilled username prefix //force needed due to the prefilled username prefix
cy.get('[formcontrolname="userName"]') cy.get('[formcontrolname="userName"]').type(testMachineUserNameAdd);
.type(testMachineUserNameAdd); cy.get('[formcontrolname="name"]').type('e2emachinename');
cy.get('[formcontrolname="name"]') cy.get('[formcontrolname="description"]').type('e2emachinedescription');
.type("e2emachinename");
cy.get('[formcontrolname="description"]')
.type("e2emachinedescription");
cy.get('[data-e2e="create-button"]').click(); cy.get('[data-e2e="create-button"]').click();
cy.get(".data-e2e-success"); cy.get('.data-e2e-success');
cy.wait(200); 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", () => { describe('remove', () => {
before("ensure it exists", () => { before('ensure it exists', () => {
apiAuth().then((api) => { apiAuth().then((api) => {
ensureMachineUserExists(api, testMachineUserNameRemove).then(() => { ensureMachineUserExists(api, testMachineUserNameRemove).then(() => {
cy.visit(machinesPath); cy.visit(machinesPath);
@ -48,19 +39,19 @@ describe("machines", () => {
}); });
}); });
it("should delete a machine", () => { it('should delete a machine', () => {
cy.contains("tr", testMachineUserNameRemove) cy.contains('tr', testMachineUserNameRemove)
// doesn't work, need to force click. // doesn't work, need to force click.
// .trigger('mouseover') // .trigger('mouseover')
.find('[data-e2e="enabled-delete-button"]') .find('[data-e2e="enabled-delete-button"]')
.click({force: true}); .click({ force: true });
cy.get('[data-e2e="confirm-dialog-input"]') cy.get('[data-e2e="confirm-dialog-input"]')
.focus() .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="confirm-dialog-button"]').click();
cy.get(".data-e2e-success"); cy.get('.data-e2e-success');
cy.wait(200); cy.wait(200);
cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
}); });
}); });
}); });

View File

@ -1,49 +1,44 @@
import { apiAuth } from "../../support/api/apiauth"; import { apiAuth } from '../../support/api/apiauth';
import { ensureProjectExists, ensureProjectResourceDoesntExist, Roles } from "../../support/api/projects"; import { ensureProjectExists, ensureProjectResourceDoesntExist, Roles } from '../../support/api/projects';
describe('permissions', () => { describe('permissions', () => {
const testProjectName = 'e2eprojectpermission';
const testAppName = 'e2eapppermission';
const testRoleName = 'e2eroleundertestname';
const testRoleDisplay = 'e2eroleundertestdisplay';
const testRoleGroup = 'e2eroleundertestgroup';
const testGrantName = 'e2egrantundertest';
const testProjectName = 'e2eprojectpermission' var projectId: number;
const testAppName = 'e2eapppermission'
const testRoleName = 'e2eroleundertestname'
const testRoleDisplay = 'e2eroleundertestdisplay'
const testRoleGroup = 'e2eroleundertestgroup'
const testGrantName = 'e2egrantundertest'
var projectId: number beforeEach(() => {
apiAuth().then((apiCalls) => {
ensureProjectExists(apiCalls, testProjectName).then((projId) => {
projectId = projId;
});
});
});
describe('add role', () => {
beforeEach(() => { beforeEach(() => {
apiAuth().then(apiCalls => { apiAuth().then((api) => {
ensureProjectExists(apiCalls, testProjectName).then(projId => { ensureProjectResourceDoesntExist(api, projectId, Roles, testRoleName);
projectId = projId cy.visit(`/projects/${projectId}?id=roles`);
}) });
}) });
})
describe('add role', () => { it('should add a role', () => {
beforeEach(()=> { cy.get('[data-e2e="add-new-role"]').click();
apiAuth().then((api)=> { cy.get('[formcontrolname="key"]').type(testRoleName);
ensureProjectResourceDoesntExist(api, projectId, Roles, testRoleName) cy.get('[formcontrolname="displayName"]').type(testRoleDisplay);
cy.visit(`/projects/${projectId}?id=roles`) cy.get('[formcontrolname="group"]').type(testRoleGroup);
}) cy.get('[data-e2e="save-button"]').click();
}) cy.get('.data-e2e-success');
cy.wait(200);
it('should add a role', () => { cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
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', () => { describe('permissions', () => {
@ -112,4 +107,4 @@ describe('permissions', () => {
}) })
}) })
*/ */

View File

@ -1,15 +1,12 @@
import { apiAuth } from "../../support/api/apiauth"; import { apiAuth } from '../../support/api/apiauth';
import { import { ensureProjectDoesntExist, ensureProjectExists } from '../../support/api/projects';
ensureProjectDoesntExist,
ensureProjectExists,
} from "../../support/api/projects";
describe("projects", () => { describe('projects', () => {
const testProjectNameCreate = "e2eprojectcreate"; const testProjectNameCreate = 'e2eprojectcreate';
const testProjectNameDeleteList = "e2eprojectdeletelist"; const testProjectNameDeleteList = 'e2eprojectdeletelist';
const testProjectNameDeleteGrid = "e2eprojectdeletegrid"; const testProjectNameDeleteGrid = 'e2eprojectdeletegrid';
describe("add project", () => { describe('add project', () => {
beforeEach(`ensure it doesn't exist already`, () => { beforeEach(`ensure it doesn't exist already`, () => {
apiAuth().then((api) => { apiAuth().then((api) => {
ensureProjectDoesntExist(api, testProjectNameCreate); ensureProjectDoesntExist(api, testProjectNameCreate);
@ -17,60 +14,56 @@ describe("projects", () => {
cy.visit(`/projects`); cy.visit(`/projects`);
}); });
it("should add a project", () => { it('should add a project', () => {
cy.get(".add-project-button").click({ force: true }); cy.get('.add-project-button').click({ force: true });
cy.get("input").type(testProjectNameCreate); cy.get('input').type(testProjectNameCreate);
cy.get('[data-e2e="continue-button"]').click(); cy.get('[data-e2e="continue-button"]').click();
cy.get(".data-e2e-success"); cy.get('.data-e2e-success');
cy.wait(200); 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('remove project', () => {
describe("list view", () => { describe('list view', () => {
beforeEach("ensure it exists", () => { beforeEach('ensure it exists', () => {
apiAuth().then((api) => { apiAuth().then((api) => {
ensureProjectExists(api, testProjectNameDeleteList); ensureProjectExists(api, testProjectNameDeleteList);
}); });
cy.visit(`/projects`); cy.visit(`/projects`);
}); });
it("removes the project", () => { it('removes the project', () => {
cy.get('[data-e2e="toggle-grid"]').click(); cy.get('[data-e2e="toggle-grid"]').click();
cy.get('[data-e2e="timestamp"]'); cy.get('[data-e2e="timestamp"]');
cy.contains("tr", testProjectNameDeleteList, { timeout: 1000 }) cy.contains('tr', testProjectNameDeleteList, { timeout: 1000 })
.find('[data-e2e="delete-project-button"]') .find('[data-e2e="delete-project-button"]')
.click({ force: true }); .click({ force: true });
cy.get('[data-e2e="confirm-dialog-input"]') cy.get('[data-e2e="confirm-dialog-input"]').focus().type(testProjectNameDeleteList);
.focus()
.type(testProjectNameDeleteList);
cy.get('[data-e2e="confirm-dialog-button"]').click(); cy.get('[data-e2e="confirm-dialog-button"]').click();
cy.get(".data-e2e-success"); cy.get('.data-e2e-success');
cy.wait(200); 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", () => { describe('grid view', () => {
beforeEach("ensure it exists", () => { beforeEach('ensure it exists', () => {
apiAuth().then((api) => { apiAuth().then((api) => {
ensureProjectExists(api, testProjectNameDeleteGrid); ensureProjectExists(api, testProjectNameDeleteGrid);
}); });
cy.visit(`/projects`); cy.visit(`/projects`);
}); });
it("removes the project", () => { it('removes the project', () => {
cy.contains('[data-e2e="grid-card"]', testProjectNameDeleteGrid) cy.contains('[data-e2e="grid-card"]', testProjectNameDeleteGrid)
.find('[data-e2e="delete-project-button"]') .find('[data-e2e="delete-project-button"]')
.click({force: true}); .click({ force: true });
cy.get('[data-e2e="confirm-dialog-input"]') cy.get('[data-e2e="confirm-dialog-input"]').focus().type(testProjectNameDeleteGrid);
.focus()
.type(testProjectNameDeleteGrid);
cy.get('[data-e2e="confirm-dialog-button"]').click(); cy.get('[data-e2e="confirm-dialog-button"]').click();
cy.get(".data-e2e-success"); cy.get('.data-e2e-success');
cy.wait(200); cy.wait(200);
cy.get(".data-e2e-failure", { timeout: 0 }).should("not.exist"); cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
}); });
}); });
}); });

View File

@ -1,45 +1,38 @@
import { apiAuth } from "../../support/api/apiauth"; import { apiAuth } from '../../support/api/apiauth';
import { ensureHumanUserExists } from "../../support/api/users"; import { ensureHumanUserExists } from '../../support/api/users';
import { login, User } from "../../support/login/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}"`, () => {
;[User.OrgOwner].forEach(user => { beforeEach(() => {
login(user);
describe(`as user "${user}"`, () => { cy.visit(orgPath);
// TODO: Why force?
beforeEach(()=> { cy.contains('[data-e2e="policy-card"]', 'Login Policy').contains('button', 'Modify').click({ force: true }); // TODO: select data-e2e
login(user) apiAuth().then((api) => {
cy.visit(orgPath) ensureHumanUserExists(api, User.LoginPolicyUser);
// 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', () => {
})
})
})
})
// 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', () => {});
});
});
});

View File

@ -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` [User.OrgOwner].forEach((user) => {
const testProjectName = 'e2eproject' describe(`as user "${user}"`, () => {
beforeEach(() => {
;[User.OrgOwner].forEach(user => { login(user);
cy.visit(orgPath);
describe(`as user "${user}"`, () => { // TODO: Why force?
cy.contains('[data-e2e="policy-card"]', 'Password Complexity').contains('button', 'Modify').click({ force: true }); // TODO: select data-e2e
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`)
})
})
})
// 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`);
});
});
});

View File

@ -1,15 +1,15 @@
import { login, User } from 'support/login/users' import { login, User } from 'support/login/users';
export interface apiCallProperties { export interface apiCallProperties {
authHeader: string authHeader: string;
mgntBaseURL: string mgntBaseURL: string;
} }
export function apiAuth(): Cypress.Chainable<apiCallProperties> { export function apiAuth(): Cypress.Chainable<apiCallProperties> {
return login(User.IAMAdminUser, 'Password1!', false, true).then(token => { return login(User.IAMAdminUser, 'Password1!', false, true).then((token) => {
return <apiCallProperties>{ return <apiCallProperties>{
authHeader: `Bearer ${token}`, authHeader: `Bearer ${token}`,
mgntBaseURL: `${Cypress.env("BACKEND_URL")}/management/v1/`, mgntBaseURL: `${Cypress.env('BACKEND_URL')}/management/v1/`,
} };
}) });
} }

View File

@ -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<number> { export function ensureSomethingExists(
api: apiCallProperties,
return searchSomething(api, searchPath, find).then(sRes => { searchPath: string,
if (sRes.entity) { find: (entity: any) => boolean,
return cy.wrap({ createPath: string,
id: sRes.entity.id, body: any,
initialSequence: 0 ): Cypress.Chainable<number> {
}) return searchSomething(api, searchPath, find)
} .then((sRes) => {
return cy.request({ if (sRes.entity) {
method: 'POST', return cy.wrap({
url: `${api.mgntBaseURL}${createPath}`, id: sRes.entity.id,
headers: { initialSequence: 0,
Authorization: api.authHeader });
}, }
body: body, return cy
failOnStatusCode: false, .request({
followRedirect: false, method: 'POST',
}).then(cRes => { url: `${api.mgntBaseURL}${createPath}`,
expect(cRes.status).to.equal(200) headers: {
return { Authorization: api.authHeader,
id: cRes.body.id, },
initialSequence: sRes.sequence body: body,
} failOnStatusCode: false,
followRedirect: false,
}) })
}).then((data) => { .then((cRes) => {
awaitDesired(90, (entity) => !!entity, data.initialSequence, api, searchPath, find) expect(cRes.status).to.equal(200);
return cy.wrap<number>(data.id) return {
id: cRes.body.id,
initialSequence: sRes.sequence,
};
});
}) })
.then((data) => {
awaitDesired(90, (entity) => !!entity, data.initialSequence, api, searchPath, find);
return cy.wrap<number>(data.id);
});
} }
export function ensureSomethingDoesntExist(api: apiCallProperties, searchPath: string, find: (entity: any) => boolean, deletePath: (entity: any) => string): Cypress.Chainable<null> { export function ensureSomethingDoesntExist(
api: apiCallProperties,
return searchSomething(api, searchPath, find).then(sRes => { searchPath: string,
if (!sRes.entity) { find: (entity: any) => boolean,
return cy.wrap(0) deletePath: (entity: any) => string,
} ): Cypress.Chainable<null> {
return cy.request({ return searchSomething(api, searchPath, find)
method: 'DELETE', .then((sRes) => {
url: `${api.mgntBaseURL}${deletePath(sRes.entity)}`, if (!sRes.entity) {
headers: { return cy.wrap(0);
Authorization: api.authHeader }
}, return cy
failOnStatusCode: false .request({
}).then((dRes) => { method: 'DELETE',
expect(dRes.status).to.equal(200) url: `${api.mgntBaseURL}${deletePath(sRes.entity)}`,
return sRes.sequence headers: {
Authorization: api.authHeader,
},
failOnStatusCode: false,
}) })
}).then((initialSequence) => { .then((dRes) => {
awaitDesired(90, (entity) => !entity , initialSequence, api, searchPath, find) expect(dRes.status).to.equal(200);
return null return sRes.sequence;
});
}) })
.then((initialSequence) => {
awaitDesired(90, (entity) => !entity, initialSequence, api, searchPath, find);
return null;
});
} }
type SearchResult = { type SearchResult = {
entity: any entity: any;
sequence: number sequence: number;
} };
function searchSomething(api: apiCallProperties, searchPath: string, find: (entity: any) => boolean): Cypress.Chainable<SearchResult> { function searchSomething(
api: apiCallProperties,
return cy.request({ searchPath: string,
method: 'POST', find: (entity: any) => boolean,
url: `${api.mgntBaseURL}${searchPath}`, ): Cypress.Chainable<SearchResult> {
headers: { return cy
Authorization: api.authHeader .request({
}, method: 'POST',
}).then(res => { url: `${api.mgntBaseURL}${searchPath}`,
return { headers: {
entity: res.body.result?.find(find) || null, Authorization: api.authHeader,
sequence: res.body.details.processedSequence },
}
}) })
.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) { function awaitDesired(
searchSomething(api, searchPath, find).then(resp => { trials: number,
const foundExpectedEntity = expectEntity(resp.entity) expectEntity: (entity: any) => boolean,
const foundExpectedSequence = resp.sequence > initialSequence 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) { if (!foundExpectedEntity || !foundExpectedSequence) {
expect(trials, `trying ${trials} more times`).to.be.greaterThan(0); expect(trials, `trying ${trials} more times`).to.be.greaterThan(0);
cy.wait(1000) cy.wait(1000);
awaitDesired(trials - 1, expectEntity, initialSequence, api, searchPath, find) awaitDesired(trials - 1, expectEntity, initialSequence, api, searchPath, find);
} }
}) });
} }

View File

@ -1,19 +1,18 @@
import { apiCallProperties } from "./apiauth" import { apiCallProperties } from './apiauth';
export enum Policy { export enum Policy {
Label = "label" Label = 'label',
} }
export function resetPolicy(api: apiCallProperties, policy: Policy) { export function resetPolicy(api: apiCallProperties, policy: Policy) {
cy.request({ cy.request({
method: 'DELETE', method: 'DELETE',
url: `${api.mgntBaseURL}/policies/${policy}`, url: `${api.mgntBaseURL}/policies/${policy}`,
headers: { headers: {
Authorization: api.authHeader Authorization: api.authHeader,
}, },
}).then(res => { }).then((res) => {
expect(res.status).to.equal(200) expect(res.status).to.equal(200);
return null return null;
}) });
} }

View File

@ -1,80 +1,69 @@
import { apiCallProperties } from "./apiauth" import { apiCallProperties } from './apiauth';
import { ensureSomethingDoesntExist, ensureSomethingExists } from "./ensure" import { ensureSomethingDoesntExist, ensureSomethingExists } from './ensure';
export function ensureProjectExists(api: apiCallProperties, projectName: string): Cypress.Chainable<number> { export function ensureProjectExists(api: apiCallProperties, projectName: string): Cypress.Chainable<number> {
return ensureSomethingExists(api, `projects/_search`, (project: any) => project.name === projectName, 'projects', {
return ensureSomethingExists( name: projectName,
api, });
`projects/_search`,
(project: any) => project.name === projectName,
'projects',
{ name: projectName },
)
} }
export function ensureProjectDoesntExist(api: apiCallProperties, projectName: string): Cypress.Chainable<null> { export function ensureProjectDoesntExist(api: apiCallProperties, projectName: string): Cypress.Chainable<null> {
return ensureSomethingDoesntExist(
return ensureSomethingDoesntExist( api,
api, `projects/_search`,
`projects/_search`, (project: any) => project.name === projectName,
(project: any) => project.name === projectName, (project) => `projects/${project.id}`,
(project) => `projects/${project.id}`, );
)
} }
class ResourceType { class ResourceType {
constructor( constructor(public resourcePath: string, public compareProperty: string, public identifierProperty: string) {}
public resourcePath: string,
public compareProperty: string,
public identifierProperty: string,
){}
} }
export const Apps = new ResourceType('apps', 'name', 'id') export const Apps = new ResourceType('apps', 'name', 'id');
export const Roles = new ResourceType('roles', 'key', 'key') export const Roles = new ResourceType('roles', 'key', 'key');
//export const Grants = new ResourceType('apps', 'name') //export const Grants = new ResourceType('apps', 'name')
export function ensureProjectResourceDoesntExist(
export function ensureProjectResourceDoesntExist(api: apiCallProperties, projectId: number, resourceType: ResourceType, resourceName: string): Cypress.Chainable<null> { api: apiCallProperties,
return ensureSomethingDoesntExist( projectId: number,
api, resourceType: ResourceType,
`projects/${projectId}/${resourceType.resourcePath}/_search`, resourceName: string,
(resource: any) => { ): Cypress.Chainable<null> {
return resource[resourceType.compareProperty] === resourceName return ensureSomethingDoesntExist(
}, api,
(resource) => { `projects/${projectId}/${resourceType.resourcePath}/_search`,
return `projects/${projectId}/${resourceType.resourcePath}/${resource[resourceType.identifierProperty]}` (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<number> { export function ensureApplicationExists(
api: apiCallProperties,
return ensureSomethingExists( projectId: number,
api, appName: string,
`projects/${projectId}/${Apps.resourcePath}/_search`, ): Cypress.Chainable<number> {
(resource: any) => resource.name === appName, return ensureSomethingExists(
`projects/${projectId}/${Apps.resourcePath}/oidc`, api,
{ `projects/${projectId}/${Apps.resourcePath}/_search`,
name: appName, (resource: any) => resource.name === appName,
redirectUris: [ `projects/${projectId}/${Apps.resourcePath}/oidc`,
'https://e2eredirecturl.org' {
], name: appName,
responseTypes: [ redirectUris: ['https://e2eredirecturl.org'],
"OIDC_RESPONSE_TYPE_CODE" responseTypes: ['OIDC_RESPONSE_TYPE_CODE'],
], grantTypes: ['OIDC_GRANT_TYPE_AUTHORIZATION_CODE'],
grantTypes: [ authMethodType: 'OIDC_AUTH_METHOD_TYPE_NONE',
"OIDC_GRANT_TYPE_AUTHORIZATION_CODE" postLogoutRedirectUris: ['https://e2elogoutredirecturl.org'],
], /* "clientId": "129383004379407963@e2eprojectpermission",
authMethodType: "OIDC_AUTH_METHOD_TYPE_NONE",
postLogoutRedirectUris: [
'https://e2elogoutredirecturl.org'
],
/* "clientId": "129383004379407963@e2eprojectpermission",
"clockSkew": "0s", "clockSkew": "0s",
"allowedOrigins": [ "allowedOrigins": [
"https://testurl.org" "https://testurl.org"
]*/ ]*/
}, },
) );
} }

View File

@ -1,49 +1,35 @@
import { apiCallProperties } from "./apiauth" import { apiCallProperties } from './apiauth';
import { ensureSomethingDoesntExist, ensureSomethingExists } from "./ensure" import { ensureSomethingDoesntExist, ensureSomethingExists } from './ensure';
export function ensureHumanUserExists(api: apiCallProperties, username: string): Cypress.Chainable<number> { export function ensureHumanUserExists(api: apiCallProperties, username: string): Cypress.Chainable<number> {
return ensureSomethingExists(api, 'users/_search', (user: any) => user.userName === username, 'users/human', {
return ensureSomethingExists( user_name: username,
api, profile: {
'users/_search', first_name: 'e2efirstName',
(user: any) => user.userName === username, last_name: 'e2elastName',
'users/human', },
{ email: {
user_name: username, email: 'e2e@email.ch',
profile: { },
first_name: 'e2efirstName', phone: {
last_name: 'e2elastName', phone: '+41 123456789',
}, },
email: { });
email: 'e2e@email.ch',
},
phone: {
phone: '+41 123456789',
},
})
} }
export function ensureMachineUserExists(api: apiCallProperties, username: string): Cypress.Chainable<number> { export function ensureMachineUserExists(api: apiCallProperties, username: string): Cypress.Chainable<number> {
return ensureSomethingExists(api, 'users/_search', (user: any) => user.userName === username, 'users/machine', {
return ensureSomethingExists( user_name: username,
api, name: 'e2emachinename',
'users/_search', description: 'e2emachinedescription',
(user: any) => user.userName === username, });
'users/machine',
{
user_name: username,
name: 'e2emachinename',
description: 'e2emachinedescription',
},
)
} }
export function ensureUserDoesntExist(api: apiCallProperties, username: string): Cypress.Chainable<null> { export function ensureUserDoesntExist(api: apiCallProperties, username: string): Cypress.Chainable<null> {
return ensureSomethingDoesntExist(
return ensureSomethingDoesntExist( api,
api, 'users/_search',
'users/_search', (user: any) => user.userName === username,
(user: any) => user.userName === username, (user) => `users/${user.id}`,
(user) => `users/${user.id}` );
)
} }

View File

@ -2,11 +2,11 @@
namespace Cypress { namespace Cypress {
interface Chainable { interface Chainable {
*/ */
/** /**
* Custom command that authenticates a user. * Custom command that authenticates a user.
* *
* @example cy.consolelogin('hodor', 'hodor1234') * @example cy.consolelogin('hodor', 'hodor1234')
*/ */
/* consolelogin(username: string, password: string): void /* 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', '/'); cy.location('pathname', {timeout: 5 * 1000}).should('eq', '/');
}) })
}) })
*/ */

View File

@ -14,7 +14,7 @@
// *********************************************************** // ***********************************************************
// Import commands.js using ES2015 syntax: // Import commands.js using ES2015 syntax:
import './commands' import './commands';
// Alternatively you can use CommonJS syntax: // Alternatively you can use CommonJS syntax:
// require('./commands') // require('./commands')

View File

@ -1,12 +1,10 @@
require('cypress-terminal-report/src/installLogsCollector')(); require('cypress-terminal-report/src/installLogsCollector')();
/** /**
* @type {Cypress.PluginConfig} * @type {Cypress.PluginConfig}
*/ */
module.exports = (on, config) => { module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits // `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config // `config` is the resolved Cypress config
} };
//import './commands' //import './commands'

View File

@ -1,4 +1,4 @@
import { debug } from "console"; import { debug } from 'console';
export enum User { export enum User {
OrgOwner = 'org_owner', OrgOwner = 'org_owner',
@ -23,77 +23,85 @@ export function login(
const loginUrl: string = '/ui/login'; const loginUrl: string = '/ui/login';
const issuerUrl: string = '/oauth/v2'; const issuerUrl: string = '/oauth/v2';
return cy.session( return cy
creds.username, .session(
() => { creds.username,
const cookies = new Map<string, string>(); () => {
const cookies = new Map<string, string>();
cy.intercept({ cy.intercept(
times: 6 {
}, req => { times: 6,
req.headers['cookie'] = requestCookies(cookies); },
req.continue((res) => { (req) => {
updateCookies(res.headers['set-cookie'] as string[], cookies); req.headers['cookie'] = requestCookies(cookies);
}); req.continue((res) => {
}) updateCookies(res.headers['set-cookie'] as string[], cookies);
});
},
);
let userToken: string let userToken: string;
cy.intercept({ cy.intercept(
method: 'POST', {
url: `${issuerUrl}/token`, method: 'POST',
}, req => { url: `${issuerUrl}/token`,
req.continue(res => { },
userToken = res.body["access_token"]} (req) => {
) req.continue((res) => {
}).as('token') userToken = res.body['access_token'];
});
},
).as('token');
cy.intercept({ cy.intercept({
method: 'POST', method: 'POST',
url: `${loginUrl}/password*`, url: `${loginUrl}/password*`,
times: 1, times: 1,
}).as('password'); }).as('password');
cy.visit(loginUrl, { retryOnNetworkFailure: true }); cy.visit(loginUrl, { retryOnNetworkFailure: true });
onUsernameScreen ? onUsernameScreen() : null; onUsernameScreen ? onUsernameScreen() : null;
cy.get('#loginName').type(creds.username); cy.get('#loginName').type(creds.username);
cy.get('#submit-button').click(); cy.get('#submit-button').click();
onPasswordScreen ? onPasswordScreen() : null; onPasswordScreen ? onPasswordScreen() : null;
cy.get('#password').type(creds.password); cy.get('#password').type(creds.password);
cy.get('#submit-button').click(); cy.get('#submit-button').click();
cy.wait('@password').then((interception) => { cy.wait('@password').then((interception) => {
if (interception.response.body.indexOf('Multifactor Setup') === -1){ if (interception.response.body.indexOf('Multifactor Setup') === -1) {
return return;
} }
cy.contains('button', 'skip').click() cy.contains('button', 'skip').click();
cy.get('#change-old-password').type(creds.password) cy.get('#change-old-password').type(creds.password);
cy.get('#change-new-password').type(creds.password) cy.get('#change-new-password').type(creds.password);
cy.get('#change-password-confirmation').type(creds.password) cy.get('#change-password-confirmation').type(creds.password);
cy.contains('button', 'next').click() cy.contains('button', 'next').click();
cy.contains('button', 'next').click() cy.contains('button', 'next').click();
}) });
cy.wait('@token').then(() => { cy.wait('@token').then(() => {
cy.task('safetoken', {key: creds.username, token: userToken}) cy.task('safetoken', { key: creds.username, token: userToken });
}) });
onAuthenticated ? onAuthenticated() : null; onAuthenticated ? onAuthenticated() : null;
cy.get("[data-e2e=authenticated-welcome]"); cy.get('[data-e2e=authenticated-welcome]');
},
{
validate: () => {
if (force) {
throw new Error('clear session');
}
}, },
}, {
).then(() => { validate: () => {
return cy.task('loadtoken', {key: creds.username}) if (force) {
}); throw new Error('clear session');
}
},
},
)
.then(() => {
return cy.task('loadtoken', { key: creds.username });
});
} }
export function loginname(withoutDomain: string, org?: string): string { 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) { function credentials(user: User, pw?: string) {
// TODO: ugly // TODO: ugly
const woDomain = user == User.IAMAdminUser ? User.IAMAdminUser : `${user}_user_name` const woDomain = user == User.IAMAdminUser ? User.IAMAdminUser : `${user}_user_name`;
const org = Cypress.env('ORGANIZATION') ? Cypress.env('ORGANIZATION') : 'zitadel' const org = Cypress.env('ORGANIZATION') ? Cypress.env('ORGANIZATION') : 'zitadel';
return { return {
username: loginname(woDomain, org), username: loginname(woDomain, org),

View File

@ -22,7 +22,7 @@ services:
image: 'cockroachdb/cockroach:v22.1.0' image: 'cockroachdb/cockroach:v22.1.0'
command: 'start-single-node --insecure --http-addr :9090' command: 'start-single-node --insecure --http-addr :9090'
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9090/health?ready=1"] test: ['CMD', 'curl', '-f', 'http://localhost:9090/health?ready=1']
interval: '10s' interval: '10s'
timeout: '30s' timeout: '30s'
retries: 5 retries: 5
@ -36,10 +36,11 @@ services:
prepare: prepare:
image: node:18-alpine3.15 image: node:18-alpine3.15
working_dir: /e2e working_dir: /e2e
user: "$UID" user: '$UID'
volumes: volumes:
- .:/e2e - .:/e2e
command: "npm ci --omit=dev && npx run wait-on http://localhost:8080" command: 'sh -c "npm ci --omit=dev && npm run lint && npx wait-on http://localhost:8080/debug/ready"'
network_mode: host
e2e: e2e:
image: cypress/included:10.3.0 image: cypress/included:10.3.0
@ -51,9 +52,9 @@ services:
prepare: prepare:
condition: 'service_completed_successfully' condition: 'service_completed_successfully'
working_dir: /e2e working_dir: /e2e
user: "$UID" user: '$UID'
volumes: volumes:
- .:/e2e - .:/e2e
network_mode: host network_mode: host
networks: networks:

34
e2e/package-lock.json generated
View File

@ -11,7 +11,8 @@
"debug": "^4.3.4", "debug": "^4.3.4",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"mochawesome": "^7.1.3", "mochawesome": "^7.1.3",
"typescript": "^4.7.4", "prettier": "^2.7.1",
"typescript": "^4.8.3",
"wait-on": "^6.0.1" "wait-on": "^6.0.1"
}, },
"devDependencies": { "devDependencies": {
@ -2125,6 +2126,20 @@
"node": ">=0.10.0" "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": { "node_modules/pretty-bytes": {
"version": "5.6.0", "version": "5.6.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
@ -2544,9 +2559,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.7.4", "version": "4.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz",
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -4327,6 +4342,11 @@
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
"dev": true "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": { "pretty-bytes": {
"version": "5.6.0", "version": "5.6.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
@ -4643,9 +4663,9 @@
"dev": true "dev": true
}, },
"typescript": { "typescript": {
"version": "4.7.4", "version": "4.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz",
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig=="
}, },
"universalify": { "universalify": {
"version": "2.0.0", "version": "2.0.0",

View File

@ -5,15 +5,18 @@
"open": "npx cypress open", "open": "npx cypress open",
"e2e": "npx cypress run", "e2e": "npx cypress run",
"open:dev": "CYPRESS_BASE_URL=http://localhost:4200 CYPRESS_BACKEND_URL=http://localhost:8080 npm run open", "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, "private": true,
"dependencies": { "dependencies": {
"debug": "^4.3.4", "debug": "^4.3.4",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"mochawesome": "^7.1.3", "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": { "devDependencies": {
"@types/node": "^18.7.13", "@types/node": "^18.7.13",