Max Peintner fc99ec87c5
ci(e2e): Run Tests in Pipelines (#3903)
* cy10 changes

* test: setup local e2e env

* test(e2e): migrate e2e setup

* add more config

* make e2e setup work

* align variables

* fix config

* skip mfa

* set user register to false

* read ids from database if not provided

* don't read ids withing env file

* fix escaping in id queries

* fix project root

* export projectRoot path

* export projectRoot

* add e2e-setup.sh

* specify GOOS and GOARCH for dockerfile compatible binary

* add org default redirect uri

* correctly initialize org policy

* await ids

* fix awaiting ids

* fix cypress configuration

* fix some tests

* initial compose setup

* fix working directory

* fix references

* make tests less flaky

* run go tests

* compose works until e2e-setup incl

* pass created e2e sa key

* make cypress run

* derive e2e orgs domain from baseurl

* use host from baseurl for setup ctx

* move defaults.yaml back to cmd pkg

* just create org owner

* Don't render element if no roles are passed

* use map instead of switchMap

* fix e2e tests

* added testdata for e3e

* zipped dump

* removed dumpDir

* cypress workflow with compose

* quote name

* cleanup vars

* eliminate need for e2e setup

* compose has no builds anymore

* use compose run and zitadel nw

* test e2e on pr (#4114)

* test e2e on pr

* install goreleaser

* install npm dev dependencies

* run cypress wf

* dynamic release version

* skip flaky user tests

* skip flaky permissions test

* cache docker layers in pipeline

* Update .github/workflows/cypress.yml

Co-authored-by: Florian Forster <florian@caos.ch>

* align goreleaser version

* get rid of install.sh

* remove cypress-terminal-report

* Revert "remove cypress-terminal-report"

This reverts commit 254b5a1f87be71c64c1289b12fc1bf23a401ea64.

* just one npm e2e:build command

* cache npm dependencies

* install node modules using docker

* dedicated e2e context

* fix syntax

* don't copy node modules from goreleaser

* add npm-copy target

* add tsconfig.json

* remove docker caching

* deleted unneeded shellscript

* naming and cleanup

Co-authored-by: Florian Forster <florian@caos.ch>
Co-authored-by: Christian Jakob <christian@caos.ch>

* cleanup

Co-authored-by: Elio Bischof <eliobischof@gmail.com>
Co-authored-by: Christian Jakob <christian@caos.ch>
Co-authored-by: Florian Forster <florian@caos.ch>
2022-08-05 20:00:46 +02:00

220 lines
5.9 KiB
TypeScript

import { debug } from "console";
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',
}
export function login(
user: User,
pw?: string,
force?: boolean,
skipMFAChangePW?: boolean,
onUsernameScreen?: () => void,
onPasswordScreen?: () => void,
onAuthenticated?: () => void,
): Cypress.Chainable<string> {
let creds = credentials(user, pw);
const loginUrl: string = '/ui/login';
const issuerUrl: string = '/oauth/v2';
const otherZitadelIdpInstance: boolean = Cypress.env('otherZitadelIdpInstance');
return cy.session(
creds.username,
() => {
const cookies = new Map<string, string>();
cy.intercept(
{
method: 'GET',
url: `${loginUrl}*`,
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: `${loginUrl}/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: `${loginUrl}/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: `${loginUrl}/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: `${issuerUrl}/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: `${issuerUrl}/authorize*`,
times: 1,
},
(req) => {
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')
cy.visit(loginUrl, { 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();
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.wait('@token').then(() => {
cy.task('safetoken', {key: creds.username, token: userToken})
})
onAuthenticated ? onAuthenticated() : null;
otherZitadelIdpInstance && cy.wait('@callback');
cy.location('pathname', { timeout: 5 * 1000 }).should('eq', '/ui/console/');
},
{
validate: () => {
if (force) {
throw new Error('clear session');
}
},
},
).then(() => {
return cy.task('loadtoken', {key: creds.username})
});
}
export function loginname(withoutDomain: string, org?: string): string {
return `${withoutDomain}@${org}.${host(Cypress.config('baseUrl'))}`;
}
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'
return {
username: loginname(woDomain, 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));
});
});
}
function requestCookies(currentCookies: Map<string, string>): string[] {
let list: Array<string> = [];
currentCookies.forEach((val, key) => {
list.push(key + '=' + val);
});
return list;
}
export function host(url: string): string {
return stripPort(stripProtocol(url));
}
function stripPort(s: string): string {
const idx = s.indexOf(':');
return idx === -1 ? s : s.substring(0, idx);
}
function stripProtocol(url: string): string {
return url.replace('http://', '').replace('https://', '');
}