feat: rehauled console (#3525)

* new console

* move npm ci to angular build

* rel path for assets

* local grpc copy

* login policy, rm clear views, features rel path

* lock

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Max Peintner
2022-04-28 12:35:02 +02:00
committed by GitHub
parent 00f7dbe875
commit 08ae39ae19
668 changed files with 47747 additions and 19118 deletions

View File

@@ -0,0 +1,50 @@
import { login, User } from "../../support/login/users";
import { Apps, ensureProjectExists, ensureProjectResourceDoesntExist } from "../../support/api/projects";
import { apiAuth } from "../../support/api/apiauth";
describe('applications', () => {
const testProjectName = 'e2eprojectapplication'
const testAppName = 'e2eappundertest'
;[User.OrgOwner].forEach(user => {
describe(`as user "${user}"`, () => {
beforeEach(`ensure it doesn't exist already`, () => {
login(user)
apiAuth().then(api => {
ensureProjectExists(api, testProjectName).then(projectID => {
ensureProjectResourceDoesntExist(api, projectID, Apps, testAppName).then(() => {
cy.visit(`${Cypress.env('consoleUrl')}/projects/${projectID}`)
})
})
})
})
it('add app', () => {
cy.get('mat-spinner')
cy.get('mat-spinner').should('not.exist')
cy.get('[data-e2e="app-card-add"]').should('be.visible').click()
// select webapp
cy.get('[formcontrolname="name"]').type(testAppName)
cy.get('[for="WEB"]').click()
cy.get('[data-e2e="continue-button-nameandtype"]').click()
//select authentication
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('[data-e2e="continue-button-redirecturis"]').click()
cy.get('[data-e2e="create-button"]').click().then(() => {
cy.get('[id*=overlay]').should('exist')
})
cy.get('.data-e2e-success')
cy.wait(200)
cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist')
//TODO: check client ID/Secret
})
})
})
})

View File

@@ -0,0 +1,83 @@
import { apiAuth } from '../../support/api/apiauth';
import { ensureHumanUserExists, ensureUserDoesntExist } from '../../support/api/users';
import { login, User, username } from '../../support/login/users';
describe('humans', () => {
const humansPath = `${Cypress.env('consoleUrl')}/users?type=human`;
const testHumanUserNameAdd = 'e2ehumanusernameadd';
const testHumanUserNameRemove = 'e2ehumanusernameremove';
[User.OrgOwner].forEach((user) => {
describe(`as user "${user}"`, () => {
beforeEach(() => {
login(user);
cy.visit(humansPath);
cy.get('[data-cy=timestamp]');
});
describe('add', () => {
before(`ensure it doesn't exist already`, () => {
apiAuth().then((apiCallProperties) => {
ensureUserDoesntExist(apiCallProperties, testHumanUserNameAdd);
});
});
it('should add a user', () => {
cy.get('a[href="/users/create"]').click();
cy.url().should('contain', 'users/create');
cy.get('[formcontrolname="email"]').type(username('e2ehuman'));
//force needed due to the prefilled username prefix
cy.get('[formcontrolname="userName"]').type(testHumanUserNameAdd, { force: true });
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.wait(200);
cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
});
});
describe('remove', () => {
before('ensure it exists', () => {
apiAuth().then((api) => {
ensureHumanUserExists(api, testHumanUserNameRemove);
});
});
it('should delete a human user', () => {
cy.contains('tr', testHumanUserNameRemove, { timeout: 1000 })
.find('button')
//force due to angular hidden buttons
.click({ force: true });
cy.get('[e2e-data="confirm-dialog-input"]').type(username(testHumanUserNameRemove, Cypress.env('org')));
cy.get('[e2e-data="confirm-dialog-button"]').click();
cy.get('.data-e2e-success');
cy.wait(200);
cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
});
});
});
});
});
/*
describe("users", ()=> {
before(()=> {
cy.consolelogin(Cypress.env('username'), Cypress.env('password'), Cypress.env('consoleUrl'))
})
it('should show personal information', () => {
cy.log(`USER: show personal information`);
//click on user information
cy.get('a[href*="users/me"').eq(0).click()
cy.url().should('contain', '/users/me')
})
it('should show users', () => {
cy.visit(Cypress.env('consoleUrl') + '/users/list/humans')
cy.url().should('contain', 'users/list/humans')
})
})
*/

View File

@@ -0,0 +1,60 @@
import { apiAuth } from '../../support/api/apiauth';
import { ensureMachineUserExists, ensureUserDoesntExist } from '../../support/api/users';
import { login, User, username } from '../../support/login/users';
describe('machines', () => {
const machinesPath = `${Cypress.env('consoleUrl')}/users?type=machine`;
const testMachineUserNameAdd = 'e2emachineusernameadd';
const testMachineUserNameRemove = 'e2emachineusernameremove';
[User.OrgOwner].forEach((user) => {
describe(`as user "${user}"`, () => {
beforeEach(() => {
login(user);
cy.visit(machinesPath);
cy.get('[data-cy=timestamp]');
});
describe('add', () => {
before(`ensure it doesn't exist already`, () => {
apiAuth().then((apiCallProperties) => {
ensureUserDoesntExist(apiCallProperties, testMachineUserNameAdd);
});
});
it('should add a machine', () => {
cy.get('a[href="/users/create-machine"]').click();
cy.url().should('contain', 'users/create-machine');
//force needed due to the prefilled username prefix
cy.get('[formcontrolname="userName"]').type(testMachineUserNameAdd, { force: true });
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.wait(200);
cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
});
});
describe('remove', () => {
before('ensure it exists', () => {
apiAuth().then((api) => {
ensureMachineUserExists(api, testMachineUserNameRemove);
});
});
it('should delete a machine', () => {
cy.contains('tr', testMachineUserNameRemove, { timeout: 1000 })
.find('button')
//force due to angular hidden buttons
.click({ force: true });
cy.get('[e2e-data="confirm-dialog-input"]').type(username(testMachineUserNameRemove, Cypress.env('org')));
cy.get('[e2e-data="confirm-dialog-button"]').click();
cy.get('.data-e2e-success');
cy.wait(200);
cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
});
});
});
});
});

View File

@@ -0,0 +1,120 @@
import { apiAuth, apiCallProperties } from "../../support/api/apiauth";
import { ensureProjectExists, ensureProjectResourceDoesntExist, Roles } from "../../support/api/projects";
import { login, User } from "../../support/login/users";
describe('permissions', () => {
const testProjectName = 'e2eprojectpermission'
const testAppName = 'e2eapppermission'
const testRoleName = 'e2eroleundertestname'
const testRoleDisplay = 'e2eroleundertestdisplay'
const testRoleGroup = 'e2eroleundertestgroup'
const testGrantName = 'e2egrantundertest'
;[User.OrgOwner].forEach(user => {
describe(`as user "${user}"`, () => {
var api: apiCallProperties
var projectId: number
beforeEach(() => {
login(user)
apiAuth().then(apiCalls => {
api = apiCalls
ensureProjectExists(apiCalls, testProjectName).then(projId => {
projectId = projId
cy.visit(`${Cypress.env('consoleUrl')}/projects/${projId}`)
})
})
})
describe('add role', () => {
beforeEach(()=> {
ensureProjectResourceDoesntExist(api, projectId, Roles, testRoleName)
})
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', () => {
before(()=> {
// cy.consolelogin(Cypress.env('username'), Cypress.env('password'), Cypress.env('consoleUrl'))
})
it('should show projects ', () => {
cy.visit(Cypress.env('consoleUrl') + '/projects')
cy.url().should('contain', '/projects')
})
it('should add a role', () => {
cy.visit(Cypress.env('consoleUrl') + '/org').then(() => {
cy.url().should('contain', '/org');
})
cy.visit(Cypress.env('consoleUrl') + '/projects').then(() => {
cy.url().should('contain', '/projects');
cy.get('.card').should('contain.text', "newProjectToTest")
})
cy.get('.card').filter(':contains("newProjectToTest")').click()
cy.get('.app-container').filter(':contains("newAppToTest")').should('be.visible').click()
let projectID
cy.url().then(url => {
cy.log(url.split('/')[4])
projectID = url.split('/')[4]
});
cy.then(() => cy.visit(Cypress.env('consoleUrl') + '/projects/' + projectID +'/roles/create'))
cy.get('[formcontrolname^=key]').type("newdemorole")
cy.get('[formcontrolname^=displayName]').type("newdemodisplayname")
cy.get('[formcontrolname^=group]').type("newdemogroupname")
cy.get('button').filter(':contains("Save")').should('be.visible').click()
//let the Role get processed
cy.wait(5000)
})
it('should add a grant', () => {
cy.visit(Cypress.env('consoleUrl') + '/org').then(() => {
cy.url().should('contain', '/org');
})
cy.visit(Cypress.env('consoleUrl') + '/projects').then(() => {
cy.url().should('contain', '/projects');
cy.get('.card').should('contain.text', "newProjectToTest")
})
cy.get('.card').filter(':contains("newProjectToTest")').click()
cy.get('.app-container').filter(':contains("newAppToTest")').should('be.visible').click()
let projectID
cy.url().then(url => {
cy.log(url.split('/')[4])
projectID = url.split('/')[4]
});
cy.then(() => cy.visit(Cypress.env('consoleUrl') + '/grant-create/project/' + projectID ))
cy.get('input').type("demo")
cy.get('[role^=listbox]').filter(`:contains("${Cypress.env("fullUserName")}")`).should('be.visible').click()
cy.wait(5000)
//cy.get('.button').contains('Continue').click()
cy.get('button').filter(':contains("Continue")').click()
cy.wait(5000)
cy.get('tr').filter(':contains("demo")').find('label').click()
cy.get('button').filter(':contains("Save")').should('be.visible').click()
//let the grant get processed
cy.wait(5000)
})
})
*/

View File

@@ -0,0 +1,78 @@
import { apiAuth } from '../../support/api/apiauth';
import { ensureProjectDoesntExist, ensureProjectExists } from '../../support/api/projects';
import { login, User } from '../../support/login/users';
describe('projects', () => {
const testProjectNameCreate = 'e2eprojectcreate';
const testProjectNameDeleteList = 'e2eprojectdeletelist';
const testProjectNameDeleteGrid = 'e2eprojectdeletegrid';
[User.OrgOwner].forEach((user) => {
describe(`as user "${user}"`, () => {
beforeEach(() => {
login(user);
});
describe('add project', () => {
beforeEach(`ensure it doesn't exist already`, () => {
apiAuth().then((api) => {
ensureProjectDoesntExist(api, testProjectNameCreate);
});
cy.visit(`${Cypress.env('consoleUrl')}/projects`);
});
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.wait(200);
cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
});
});
describe('remove project', () => {
describe('list view', () => {
beforeEach('ensure it exists', () => {
apiAuth().then((api) => {
ensureProjectExists(api, testProjectNameDeleteList);
});
cy.visit(`${Cypress.env('consoleUrl')}/projects`);
});
it('removes the project', () => {
cy.get('[data-e2e=toggle-grid]').click();
cy.get('[data-cy=timestamp]');
cy.contains('tr', testProjectNameDeleteList, { timeout: 1000 })
.find('[data-e2e=delete-project-button]')
.click({ force: true });
cy.get('[e2e-data="confirm-dialog-button"]').click();
cy.get('.data-e2e-success');
cy.wait(200);
cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
});
});
describe('grid view', () => {
beforeEach('ensure it exists', () => {
apiAuth().then((api) => {
ensureProjectExists(api, testProjectNameDeleteGrid);
});
cy.visit(`${Cypress.env('consoleUrl')}/projects`);
});
it('removes the project', () => {
cy.contains('[data-e2e=grid-card]', testProjectNameDeleteGrid)
.find('[data-e2e=delete-project-button]')
.trigger('mouseover')
.click();
cy.get('[e2e-data="confirm-dialog-button"]').click();
cy.get('.data-e2e-success');
cy.wait(200);
cy.get('.data-e2e-failure', { timeout: 0 }).should('not.exist');
});
});
});
});
});
});

View File

@@ -0,0 +1,45 @@
import { apiAuth } from "../../support/api/apiauth";
import { ensureHumanUserExists } from "../../support/api/users";
import { login, User } from "../../support/login/users";
describe("login policy", ()=> {
const orgPath = `${Cypress.env('consoleUrl')}/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', () => {
})
})
})
})

View File

@@ -0,0 +1,34 @@
import { login, User } from "../../support/login/users";
describe("password complexity", ()=> {
const orgPath = `${Cypress.env('consoleUrl')}/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`)
})
})
})

View File

@@ -0,0 +1,85 @@
import { apiAuth, apiCallProperties } from "../../support/api/apiauth";
import { Policy, resetPolicy } from "../../support/api/policies";
import { login, User } from "../../support/login/users";
describe("private labeling", ()=> {
const orgPath = `${Cypress.env('consoleUrl')}/org`
;[User.OrgOwner].forEach(user => {
describe(`as user "${user}"`, () => {
let api: apiCallProperties
beforeEach(()=> {
login(user)
cy.visit(orgPath)
// TODO: Why force?
cy.contains('[data-e2e=policy-card]', 'Private Labeling').contains('button', 'Modify').click({force: true}) // TODO: select data-e2e
})
customize('white', user)
customize('dark', user)
})
})
})
function customize(theme: string, user: User) {
describe(`${theme} theme`, () => {
beforeEach(() => {
apiAuth().then(api => {
resetPolicy(api, Policy.Label)
})
})
describe.skip('logo', () => {
beforeEach('expand logo category', () => {
cy.contains('[data-e2e=policy-category]', 'Logo').click() // TODO: select data-e2e
cy.fixture('logo.png').as('logo')
})
it('should update a logo', () => {
cy.get('[data-e2e=image-part-logo]').find('input').then(function (el) {
const blob = Cypress.Blob.base64StringToBlob(this.logo, 'image/png')
const file = new File([blob], 'images/logo.png', { type: 'image/png' })
const list = new DataTransfer()
list.items.add(file)
const myFileList = list.files
el[0].files = myFileList
el[0].dispatchEvent(new Event('change', { bubbles: true }))
})
})
it('should delete a logo')
})
it('should update an icon')
it('should delete an icon')
it.skip('should update the background color', () => {
cy.contains('[data-e2e=color]', 'Background Color').find('button').click() // TODO: select data-e2e
cy.get('color-editable-input').find('input').clear().type('#ae44dc')
cy.get('[data-e2e=save-colors-button]').click()
cy.get('[data-e2e=header-user-avatar]').click()
cy.contains('Logout All Users').click() // TODO: select data-e2e
login(User.LoginPolicyUser, true, null, () => {
cy.pause()
})
})
it('should update the primary color')
it('should update the warning color')
it('should update the font color')
it('should update the font style')
it('should hide the loginname suffix')
it('should show the loginname suffix')
it('should hide the watermark')
it('should show the watermark')
it('should show the current configuration')
it('should reset the policy')
})
}