cy10 changes

This commit is contained in:
Max Peintner 2022-07-06 09:53:26 +02:00
parent 8434eaa9c0
commit 3a13f9da2a
16 changed files with 283 additions and 236 deletions

23
console/cypress.config.ts Normal file
View File

@ -0,0 +1,23 @@
import { defineConfig } from 'cypress';
export default defineConfig({
reporter: 'mochawesome',
reporterOptions: {
reportDir: 'cypress/results',
overwrite: false,
html: true,
json: true,
},
chromeWebSecurity: false,
// experimentalSessionSupport: true,
trashAssetsBeforeRuns: false,
defaultCommandTimeout: 10000,
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});

View File

@ -1,14 +0,0 @@
{
"supportFile": "./cypress/support/index.ts",
"reporter": "mochawesome",
"reporterOptions": {
"reportDir": "cypress/results",
"overwrite": false,
"html": true,
"json": true
},
"chromeWebSecurity": false,
"experimentalSessionSupport": true,
"trashAssetsBeforeRuns": false
}

View File

@ -0,0 +1,79 @@
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, undefined, 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');
});
}

View File

@ -1,85 +0,0 @@
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')
})
}

View File

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.ts is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

View File

@ -1,164 +1,187 @@
export enum User {
OrgOwner = 'org_owner',
OrgOwnerViewer = 'org_owner_viewer',
OrgProjectCreator = 'org_project_creator',
LoginPolicyUser = 'login_policy_user',
PasswordComplexityUser = 'password_complexity_user',
IAMAdminUser = "zitadel-admin"
OrgOwner = 'org_owner',
OrgOwnerViewer = 'org_owner_viewer',
OrgProjectCreator = 'org_project_creator',
LoginPolicyUser = 'login_policy_user',
PasswordComplexityUser = 'password_complexity_user',
IAMAdminUser = 'zitadel-admin',
}
export function login(user:User, force?: boolean, pw?: string, onUsernameScreen?: () => void, onPasswordScreen?: () => void, onAuthenticated?: () => void): void {
let creds = credentials(user, pw)
export function login(
user: User,
pw?: string,
force?: boolean,
onUsernameScreen?: () => void,
onPasswordScreen?: () => void,
onAuthenticated?: () => void,
): void {
let creds = credentials(user, pw);
const accountsUrl: string = Cypress.env('accountsUrl')
const consoleUrl: string = Cypress.env('consoleUrl')
const otherZitadelIdpInstance: boolean = Cypress.env('otherZitadelIdpInstance')
const accountsUrl: string = Cypress.env('accountsUrl');
const consoleUrl: string = Cypress.env('consoleUrl');
const otherZitadelIdpInstance: boolean = Cypress.env('otherZitadelIdpInstance');
cy.session(creds.username, () => {
cy.session(
creds.username,
() => {
const cookies = new Map<string, string>();
const cookies = new Map<string, string>()
if (otherZitadelIdpInstance) {
cy.intercept(
{
method: 'GET',
url: `${accountsUrl}/login*`,
times: 1,
},
(req) => {
req.headers['cookie'] = requestCookies(cookies);
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies);
});
},
).as('login');
if (otherZitadelIdpInstance) {
cy.intercept({
method: 'GET',
url: `${accountsUrl}/login*`,
times: 1
}, (req) => {
req.headers['cookie'] = requestCookies(cookies)
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies)
})
}).as('login')
cy.intercept(
{
method: 'POST',
url: `${accountsUrl}/loginname*`,
times: 1,
},
(req) => {
req.headers['cookie'] = requestCookies(cookies);
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies);
});
},
).as('loginName');
cy.intercept({
method: 'POST',
url: `${accountsUrl}/loginname*`,
times: 1
}, (req) => {
req.headers['cookie'] = requestCookies(cookies)
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies)
})
}).as('loginName')
cy.intercept(
{
method: 'POST',
url: `${accountsUrl}/password*`,
times: 1,
},
(req) => {
req.headers['cookie'] = requestCookies(cookies);
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies);
});
},
).as('password');
cy.intercept({
method: 'POST',
url: `${accountsUrl}/password*`,
times: 1
}, (req) => {
req.headers['cookie'] = requestCookies(cookies)
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies)
})
}).as('password')
cy.intercept(
{
method: 'GET',
url: `${accountsUrl}/success*`,
times: 1,
},
(req) => {
req.headers['cookie'] = requestCookies(cookies);
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies);
});
},
).as('success');
cy.intercept({
method: 'GET',
url: `${accountsUrl}/success*`,
times: 1
}, (req) => {
req.headers['cookie'] = requestCookies(cookies)
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies)
})
}).as('success')
cy.intercept(
{
method: 'GET',
url: `${accountsUrl}/oauth/v2/authorize/callback*`,
times: 1,
},
(req) => {
req.headers['cookie'] = requestCookies(cookies);
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies);
});
},
).as('callback');
cy.intercept({
method: 'GET',
url: `${accountsUrl}/oauth/v2/authorize/callback*`,
times: 1
}, (req) => {
req.headers['cookie'] = requestCookies(cookies)
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies)
})
}).as('callback')
cy.intercept({
method: 'GET',
url: `${accountsUrl}/oauth/v2/authorize*`,
times: 1,
}, (req) => {
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies)
})
})
cy.intercept(
{
method: 'GET',
url: `${accountsUrl}/oauth/v2/authorize*`,
times: 1,
},
(req) => {
req.continue((res) => {
updateCookies(res.headers['set-cookie'] as string[], cookies);
});
},
);
}
cy.visit(`${consoleUrl}/loginname`, { retryOnNetworkFailure: true });
otherZitadelIdpInstance && cy.wait('@login');
onUsernameScreen ? onUsernameScreen() : null;
cy.get('#loginName').type(creds.username);
cy.get('#submit-button').click();
otherZitadelIdpInstance && cy.wait('@loginName');
onPasswordScreen ? onPasswordScreen() : null;
cy.get('#password').type(creds.password);
cy.get('#submit-button').click();
onAuthenticated ? onAuthenticated() : null;
otherZitadelIdpInstance && cy.wait('@callback');
cy.location('pathname', { timeout: 5 * 1000 }).should('eq', '/');
},
{
validate: () => {
if (force) {
throw new Error('clear session');
}
cy.visit(`${consoleUrl}/loginname`, { retryOnNetworkFailure: true });
otherZitadelIdpInstance && cy.wait('@login')
onUsernameScreen ? onUsernameScreen() : null
cy.get('#loginName').type(creds.username)
cy.get('#submit-button').click()
otherZitadelIdpInstance && cy.wait('@loginName')
onPasswordScreen ? onPasswordScreen() : null
cy.get('#password').type(creds.password)
cy.get('#submit-button').click()
onAuthenticated ? onAuthenticated() : null
otherZitadelIdpInstance && cy.wait('@callback')
cy.location('pathname', {timeout: 5 * 1000}).should('eq', '/');
}, {
validate: () => {
if (force) {
throw new Error("clear session");
}
cy.visit(`${consoleUrl}/users/me`)
}
})
cy.visit(`${consoleUrl}/users/me`);
},
},
);
}
export function username(withoutDomain: string, project?: string): string {
return `${withoutDomain}@${project ? `${project}.` : ''}${host(Cypress.env('apiUrl')).replace('api.', '')}`
return `${withoutDomain}@${project ? `${project}.` : ''}${host(Cypress.env('apiUrl')).replace('api.', '')}`;
}
function credentials(user: User, pw?: string) {
const isAdmin = user == User.IAMAdminUser
return {
username: username(isAdmin ? user : `${user}_user_name`, isAdmin ? 'caos-ag' : Cypress.env('org')),
password: pw ? pw : Cypress.env(`${user}_password`)
}
const isAdmin = user == User.IAMAdminUser;
return {
username: username(isAdmin ? user : `${user}_user_name`, isAdmin ? 'caos-ag' : Cypress.env('org')),
password: pw ? pw : Cypress.env(`${user}_password`),
};
}
function updateCookies(newCookies: string[] | undefined, currentCookies: Map<string, string>) {
if (newCookies === undefined) {
return
}
newCookies.forEach(cs => {
cs.split('; ').forEach(cookie => {
const idx = cookie.indexOf('=')
currentCookies.set(cookie.substring(0,idx), cookie.substring(idx+1))
})
})
if (newCookies === undefined) {
return;
}
newCookies.forEach((cs) => {
cs.split('; ').forEach((cookie) => {
const idx = cookie.indexOf('=');
currentCookies.set(cookie.substring(0, idx), cookie.substring(idx + 1));
});
});
}
function requestCookies(currentCookies: Map<string, string>): string[] {
let list: Array<string> = []
currentCookies.forEach((val, key) => {
list.push(key+"="+val)
})
return list
let list: Array<string> = [];
currentCookies.forEach((val, key) => {
list.push(key + '=' + val);
});
return list;
}
export function host(url: string): string {
return stripPort(stripProtocol(url))
return stripPort(stripProtocol(url));
}
function stripPort(s: string): string {
const idx = s.indexOf(":")
return idx === -1 ? s : s.substring(0,idx)
const idx = s.indexOf(':');
return idx === -1 ? s : s.substring(0, idx);
}
function stripProtocol(url: string): string {
return url.replace('http://', '').replace('https://', '')
return url.replace('http://', '').replace('https://', '');
}

View File

@ -1,8 +1,9 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
},
"include": ["**/*.ts"]
}
"compilerOptions": {
"baseUrl": "./",
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
},
"include": ["**/*.ts"]
}

View File

@ -6,7 +6,7 @@ E2E_ORG_PROJECT_CREATOR_PW=Password1!
E2E_PASSWORD_COMPLEXITY_USER_PW=Password1!
E2E_LOGIN_POLICY_USER_PW=Password1!
E2E_SERVICEACCOUNT_KEY_PATH="${projectRoot}/.keys/e2e.json"
E2E_CONSOLE_URL="http://localhost:4200"
E2E_CONSOLE_URL="http://localhost:4200/ui/console"
E2E_API_URL="http://localhost:50002"
E2E_ACCOUNTS_URL="http://localhost:50003"
E2E_ISSUER_URL="http://localhost:50002/oauth/v2"