fix cypress configuration

This commit is contained in:
Elio Bischof 2022-07-20 19:04:37 +02:00
parent 66b574e813
commit 960bb91de3
No known key found for this signature in database
GPG Key ID: 7B383FDE4DDBF1BD
16 changed files with 56 additions and 65 deletions

View File

@ -48,9 +48,7 @@ type E2EConfig struct {
MachineKeyPath string MachineKeyPath string
InstanceID string InstanceID string
ZitadelProjectResourceID string ZitadelProjectResourceID string
APIURL string BaseURL string
IssuerURL string
Audience string
OrgOwnerPassword string OrgOwnerPassword string
OrgOwnerViewerPassword string OrgOwnerViewerPassword string
OrgProjectCreatorPassword string OrgProjectCreatorPassword string
@ -65,12 +63,8 @@ func (e E2EConfig) Validate() (err error) {
if e.MachineKeyPath == "" { if e.MachineKeyPath == "" {
return errors.New("field MachineKeyPath is empty") return errors.New("field MachineKeyPath is empty")
} }
if e.BaseURL == "" {
if e.APIURL == "" { return errors.New("field BaseURL is empty")
return errors.New("field APIURL is empty")
}
if e.IssuerURL == "" {
return errors.New("field IssuerURL is empty")
} }
if e.OrgOwnerPassword == "" { if e.OrgOwnerPassword == "" {
return errors.New("field OrgOwnerPassword is empty") return errors.New("field OrgOwnerPassword is empty")

View File

@ -3,9 +3,7 @@ E2E:
ZitadelProjectResourceID: "" ZitadelProjectResourceID: ""
Org: "e2e-tests" Org: "e2e-tests"
MachineKeyPath: ".keys/e2e.json" MachineKeyPath: ".keys/e2e.json"
APIURL: "http://localhost:8080" BaseURL: "http://localhost:8080"
IssuerURL: "http://localhost:8080/oauth/v2"
Audience: "http://localhost:8080"
OrgOwnerPassword: "Password1!" OrgOwnerPassword: "Password1!"
OrgOwnerViewerPassword: "Password1!" OrgOwnerViewerPassword: "Password1!"
OrgProjectCreatorPassword: "Password1!" OrgProjectCreatorPassword: "Password1!"

View File

@ -17,5 +17,5 @@ fi
$NPX cypress $ACTION \ $NPX cypress $ACTION \
--port "${E2E_CYPRESSPORT}" \ --port "${E2E_CYPRESSPORT}" \
--env org="${ZITADEL_E2E_ORG}",org_owner_password="${ZITADEL_E2E_ORGOWNERPW}",org_owner_viewer_password="${ZITADEL_E2E_ORGOWNERVIEWERPW}",org_project_creator_password="${ZITADEL_E2E_ORGPROJECTCREATORPW}",login_policy_user_password="${ZITADEL_E2E_LOGINPOLICYUSERPW}",password_complexity_user_password="${ZITADEL_E2E_PASSWORDCOMPLEXITYUSERPW}",consoleUrl="${ZITADEL_E2E_CONSOLEURL}",apiUrl="${ZITADEL_E2E_APIURL}",accountsUrl="${ZITADEL_E2E_ACCOUNTSURL}",issuerUrl="${ZITADEL_E2E_ISSUERURL}",serviceAccountKeyPath="${ZITADEL_E2E_MACHINEKEYPATH}",otherZitadelIdpInstance="${ZITADEL_E2E_OTHERZITADELIDPINSTANCE}",zitadelProjectResourceId="${ZITADEL_E2E_ZITADELPROJECTRESOURCEID}" \ --env org="${ZITADEL_E2E_ORG}",org_owner_password="${ZITADEL_E2E_ORGOWNERPW}",org_owner_viewer_password="${ZITADEL_E2E_ORGOWNERVIEWERPW}",org_project_creator_password="${ZITADEL_E2E_ORGPROJECTCREATORPW}",login_policy_user_password="${ZITADEL_E2E_LOGINPOLICYUSERPW}",password_complexity_user_password="${ZITADEL_E2E_PASSWORDCOMPLEXITYUSERPW}",baseUrl="${ZITADEL_E2E_BASEURL}",serviceAccountKeyPath="${ZITADEL_E2E_MACHINEKEYPATH}",otherZitadelIdpInstance="${ZITADEL_E2E_OTHERZITADELIDPINSTANCE}",zitadelProjectResourceId="${ZITADEL_E2E_ZITADELPROJECTRESOURCEID}" \
"$@" "$@"

View File

@ -16,7 +16,7 @@ describe('applications', () => {
apiAuth().then(api => { apiAuth().then(api => {
ensureProjectExists(api, testProjectName).then(projectID => { ensureProjectExists(api, testProjectName).then(projectID => {
ensureProjectResourceDoesntExist(api, projectID, Apps, testAppName).then(() => { ensureProjectResourceDoesntExist(api, projectID, Apps, testAppName).then(() => {
cy.visit(`${Cypress.env('consoleUrl')}/projects/${projectID}`) cy.visit(`${Cypress.env('baseUrl')}/ui/console/projects/${projectID}`)
}) })
}) })
}) })
@ -46,5 +46,5 @@ describe('applications', () => {
//TODO: check client ID/Secret //TODO: check client ID/Secret
}) })
}) })
}) })
}) })

View File

@ -3,7 +3,7 @@ import { ensureHumanUserExists, ensureUserDoesntExist } from '../../support/api/
import { login, User, username } from '../../support/login/users'; import { login, User, username } from '../../support/login/users';
describe('humans', () => { describe('humans', () => {
const humansPath = `${Cypress.env('consoleUrl')}/users?type=human`; const humansPath = `${Cypress.env('baseUrl')}/ui/console/users?type=human`;
const testHumanUserNameAdd = 'e2ehumanusernameadd'; const testHumanUserNameAdd = 'e2ehumanusernameadd';
const testHumanUserNameRemove = 'e2ehumanusernameremove'; const testHumanUserNameRemove = 'e2ehumanusernameremove';
@ -64,18 +64,18 @@ describe('humans', () => {
describe("users", ()=> { describe("users", ()=> {
before(()=> { before(()=> {
cy.consolelogin(Cypress.env('username'), Cypress.env('password'), Cypress.env('consoleUrl')) cy.consolelogin(Cypress.env('username'), Cypress.env('password'), `Cypress.env('baseUrl')/ui/console`)
}) })
it('should show personal information', () => { it('should show personal information', () => {
cy.log(`USER: show personal information`); cy.log(`USER: show personal information`);
//click on user information //click on user information
cy.get('a[href*="users/me"').eq(0).click() cy.get('a[href*="users/me"').eq(0).click()
cy.url().should('contain', '/users/me') cy.url().should('contain', '/users/me')
}) })
it('should show users', () => { it('should show users', () => {
cy.visit(Cypress.env('consoleUrl') + '/users/list/humans') cy.visit(Cypress.env('baseUrl')/ui/console + '/users/list/humans')
cy.url().should('contain', 'users/list/humans') cy.url().should('contain', 'users/list/humans')
}) })
}) })

View File

@ -3,7 +3,7 @@ import { ensureMachineUserExists, ensureUserDoesntExist } from '../../support/ap
import { login, User, username } from '../../support/login/users'; import { login, User, username } from '../../support/login/users';
describe('machines', () => { describe('machines', () => {
const machinesPath = `${Cypress.env('consoleUrl')}/users?type=machine`; const machinesPath = `${Cypress.env('baseUrl')}/ui/console/users?type=machine`;
const testMachineUserNameAdd = 'e2emachineusernameadd'; const testMachineUserNameAdd = 'e2emachineusernameadd';
const testMachineUserNameRemove = 'e2emachineusernameremove'; const testMachineUserNameRemove = 'e2emachineusernameremove';

View File

@ -24,7 +24,7 @@ describe('permissions', () => {
api = apiCalls api = apiCalls
ensureProjectExists(apiCalls, testProjectName).then(projId => { ensureProjectExists(apiCalls, testProjectName).then(projId => {
projectId = projId projectId = projId
cy.visit(`${Cypress.env('consoleUrl')}/projects/${projId}`) cy.visit(`${Cypress.env('baseUrl')}/ui/console/projects/${projId}`)
}) })
}) })
}) })
@ -54,19 +54,19 @@ describe('permissions', () => {
describe('permissions', () => { describe('permissions', () => {
before(()=> { before(()=> {
// cy.consolelogin(Cypress.env('username'), Cypress.env('password'), Cypress.env('consoleUrl')) // cy.consolelogin(Cypress.env('username'), Cypress.env('password'), Cypress.env('baseUrl')/ui/console)
}) })
it('should show projects ', () => { it('should show projects ', () => {
cy.visit(Cypress.env('consoleUrl') + '/projects') cy.visit(Cypress.env('baseUrl')/ui/console + '/projects')
cy.url().should('contain', '/projects') cy.url().should('contain', '/projects')
}) })
it('should add a role', () => { it('should add a role', () => {
cy.visit(Cypress.env('consoleUrl') + '/org').then(() => { cy.visit(Cypress.env('baseUrl')/ui/console + '/org').then(() => {
cy.url().should('contain', '/org'); cy.url().should('contain', '/org');
}) })
cy.visit(Cypress.env('consoleUrl') + '/projects').then(() => { cy.visit(Cypress.env('baseUrl')/ui/console + '/projects').then(() => {
cy.url().should('contain', '/projects'); cy.url().should('contain', '/projects');
cy.get('.card').should('contain.text', "newProjectToTest") cy.get('.card').should('contain.text', "newProjectToTest")
}) })
@ -77,8 +77,8 @@ describe('permissions', () => {
cy.log(url.split('/')[4]) cy.log(url.split('/')[4])
projectID = url.split('/')[4] projectID = url.split('/')[4]
}); });
cy.then(() => cy.visit(Cypress.env('consoleUrl') + '/projects/' + projectID +'/roles/create')) cy.then(() => cy.visit(Cypress.env('baseUrl')/ui/console + '/projects/' + projectID +'/roles/create'))
cy.get('[formcontrolname^=key]').type("newdemorole") cy.get('[formcontrolname^=key]').type("newdemorole")
cy.get('[formcontrolname^=displayName]').type("newdemodisplayname") cy.get('[formcontrolname^=displayName]').type("newdemodisplayname")
cy.get('[formcontrolname^=group]').type("newdemogroupname") cy.get('[formcontrolname^=group]').type("newdemogroupname")
@ -88,10 +88,10 @@ describe('permissions', () => {
}) })
it('should add a grant', () => { it('should add a grant', () => {
cy.visit(Cypress.env('consoleUrl') + '/org').then(() => { cy.visit(Cypress.env('baseUrl')/ui/console + '/org').then(() => {
cy.url().should('contain', '/org'); cy.url().should('contain', '/org');
}) })
cy.visit(Cypress.env('consoleUrl') + '/projects').then(() => { cy.visit(Cypress.env('baseUrl')/ui/console + '/projects').then(() => {
cy.url().should('contain', '/projects'); cy.url().should('contain', '/projects');
cy.get('.card').should('contain.text', "newProjectToTest") cy.get('.card').should('contain.text', "newProjectToTest")
}) })
@ -102,8 +102,8 @@ describe('permissions', () => {
cy.log(url.split('/')[4]) cy.log(url.split('/')[4])
projectID = url.split('/')[4] projectID = url.split('/')[4]
}); });
cy.then(() => cy.visit(Cypress.env('consoleUrl') + '/grant-create/project/' + projectID )) cy.then(() => cy.visit(Cypress.env('baseUrl')/ui/console + '/grant-create/project/' + projectID ))
cy.get('input').type("demo") cy.get('input').type("demo")
cy.get('[role^=listbox]').filter(`:contains("${Cypress.env("fullUserName")}")`).should('be.visible').click() cy.get('[role^=listbox]').filter(`:contains("${Cypress.env("fullUserName")}")`).should('be.visible').click()
cy.wait(5000) cy.wait(5000)

View File

@ -18,7 +18,7 @@ describe('projects', () => {
apiAuth().then((api) => { apiAuth().then((api) => {
ensureProjectDoesntExist(api, testProjectNameCreate); ensureProjectDoesntExist(api, testProjectNameCreate);
}); });
cy.visit(`${Cypress.env('consoleUrl')}/projects`); cy.visit(`${Cypress.env('baseUrl')}/ui/console/projects`);
}); });
it('should add a project', () => { it('should add a project', () => {
@ -37,7 +37,7 @@ describe('projects', () => {
apiAuth().then((api) => { apiAuth().then((api) => {
ensureProjectExists(api, testProjectNameDeleteList); ensureProjectExists(api, testProjectNameDeleteList);
}); });
cy.visit(`${Cypress.env('consoleUrl')}/projects`); cy.visit(`${Cypress.env('baseUrl')}/ui/console/projects`);
}); });
it('removes the project', () => { it('removes the project', () => {
@ -58,7 +58,7 @@ describe('projects', () => {
apiAuth().then((api) => { apiAuth().then((api) => {
ensureProjectExists(api, testProjectNameDeleteGrid); ensureProjectExists(api, testProjectNameDeleteGrid);
}); });
cy.visit(`${Cypress.env('consoleUrl')}/projects`); cy.visit(`${Cypress.env('baseUrl')}/ui/console/projects`);
}); });
it('removes the project', () => { it('removes the project', () => {

View File

@ -4,7 +4,7 @@ import { login, User } from "../../support/login/users";
describe("login policy", ()=> { describe("login policy", ()=> {
const orgPath = `${Cypress.env('consoleUrl')}/org` const orgPath = `${Cypress.env('baseUrl')}/ui/console/org`
;[User.OrgOwner].forEach(user => { ;[User.OrgOwner].forEach(user => {

View File

@ -2,7 +2,7 @@ import { login, User } from "../../support/login/users";
describe("password complexity", ()=> { describe("password complexity", ()=> {
const orgPath = `${Cypress.env('consoleUrl')}/org` const orgPath = `${Cypress.env('baseUrl')}/ui/console/org`
const testProjectName = 'e2eproject' const testProjectName = 'e2eproject'
;[User.OrgOwner].forEach(user => { ;[User.OrgOwner].forEach(user => {

View File

@ -3,7 +3,7 @@ import { Policy, resetPolicy } from '../../support/api/policies';
import { login, User } from '../../support/login/users'; import { login, User } from '../../support/login/users';
describe('private labeling', () => { describe('private labeling', () => {
const orgPath = `${Cypress.env('consoleUrl')}/org`; const orgPath = `${Cypress.env('baseUrl')}/ui/console/org`;
[User.OrgOwner].forEach((user) => { [User.OrgOwner].forEach((user) => {
describe(`as user "${user}"`, () => { describe(`as user "${user}"`, () => {

View File

@ -6,8 +6,8 @@ export interface apiCallProperties {
} }
export function apiAuth(): Cypress.Chainable<apiCallProperties> { export function apiAuth(): Cypress.Chainable<apiCallProperties> {
const apiUrl = Cypress.env('apiUrl') const baseUrl = Cypress.env('baseUrl')
const issuerUrl = Cypress.env('issuerUrl') const issuerUrl = `${baseUrl}/oauth/v2`
const zitadelProjectResourceID = (<string>Cypress.env('zitadelProjectResourceId')).replace('bignumber-', '') const zitadelProjectResourceID = (<string>Cypress.env('zitadelProjectResourceId')).replace('bignumber-', '')
const key = Cypress.env("parsedServiceAccountKey") const key = Cypress.env("parsedServiceAccountKey")
@ -18,7 +18,7 @@ export function apiAuth(): Cypress.Chainable<apiCallProperties> {
const bearerToken = sign({ const bearerToken = sign({
iss: key.userId, iss: key.userId,
sub: key.userId, sub: key.userId,
aud: `${issuerUrl}`, aud: `${baseUrl}`,
iat: iat, iat: iat,
exp: exp exp: exp
}, key.key, { }, key.key, {
@ -30,7 +30,7 @@ export function apiAuth(): Cypress.Chainable<apiCallProperties> {
return cy.request({ return cy.request({
method: 'POST', method: 'POST',
url: `${apiUrl}/oauth/v2/token`, url: `${issuerUrl}/token`,
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded'
}, },
@ -43,7 +43,7 @@ export function apiAuth(): Cypress.Chainable<apiCallProperties> {
return <apiCallProperties>{ return <apiCallProperties>{
authHeader: `Bearer ${token}`, authHeader: `Bearer ${token}`,
mgntBaseURL: `${apiUrl}/management/v1/`, mgntBaseURL: `${baseUrl}/management/v1/`,
} }
}) })
} }

View File

@ -7,14 +7,14 @@ namespace Cypress {
* *
* @example cy.consolelogin('hodor', 'hodor1234') * @example cy.consolelogin('hodor', 'hodor1234')
*/ */
/* consolelogin(username: string, password: string): void /* consolelogin(username: string, password: string): void
} }
} }
Cypress.Commands.add('consolelogin', { prevSubject: false }, (username: string, password: string) => { Cypress.Commands.add('consolelogin', { prevSubject: false }, (username: string, password: string) => {
window.sessionStorage.removeItem("zitadel:access_token") window.sessionStorage.removeItem("zitadel:access_token")
cy.visit(Cypress.env('consoleUrl')).then(() => { cy.visit(Cypress.env('baseUrl')/ui/console).then(() => {
// fill the fields and push button // fill the fields and push button
cy.get('#loginName').type(username, { log: false }) cy.get('#loginName').type(username, { log: false })
cy.get('#submit-button').click() cy.get('#submit-button').click()

View File

@ -4,7 +4,7 @@ export enum User {
OrgProjectCreator = 'org_project_creator', OrgProjectCreator = 'org_project_creator',
LoginPolicyUser = 'login_policy_user', LoginPolicyUser = 'login_policy_user',
PasswordComplexityUser = 'password_complexity_user', PasswordComplexityUser = 'password_complexity_user',
IAMAdminUser = 'zitadel-admin', // IAMAdminUser = 'zitadel-admin',
} }
export function login( export function login(
@ -17,8 +17,10 @@ export function login(
): void { ): void {
let creds = credentials(user, pw); let creds = credentials(user, pw);
const accountsUrl: string = Cypress.env('accountsUrl'); const baseUrl: string = Cypress.env('baseUrl');
const consoleUrl: string = Cypress.env('consoleUrl'); const consoleUrl: string = `${baseUrl}/ui/console`;
const loginUrl: string = `${baseUrl}/ui/login`;
const issuerUrl: string = `${baseUrl}/oauth/v2`;
const otherZitadelIdpInstance: boolean = Cypress.env('otherZitadelIdpInstance'); const otherZitadelIdpInstance: boolean = Cypress.env('otherZitadelIdpInstance');
cy.session( cy.session(
@ -30,7 +32,7 @@ export function login(
cy.intercept( cy.intercept(
{ {
method: 'GET', method: 'GET',
url: `${accountsUrl}/login*`, url: `${loginUrl}*`,
times: 1, times: 1,
}, },
(req) => { (req) => {
@ -44,7 +46,7 @@ export function login(
cy.intercept( cy.intercept(
{ {
method: 'POST', method: 'POST',
url: `${accountsUrl}/loginname*`, url: `${loginUrl}/loginname*`,
times: 1, times: 1,
}, },
(req) => { (req) => {
@ -58,7 +60,7 @@ export function login(
cy.intercept( cy.intercept(
{ {
method: 'POST', method: 'POST',
url: `${accountsUrl}/password*`, url: `${loginUrl}/password*`,
times: 1, times: 1,
}, },
(req) => { (req) => {
@ -72,7 +74,7 @@ export function login(
cy.intercept( cy.intercept(
{ {
method: 'GET', method: 'GET',
url: `${accountsUrl}/success*`, url: `${loginUrl}/success*`,
times: 1, times: 1,
}, },
(req) => { (req) => {
@ -86,7 +88,7 @@ export function login(
cy.intercept( cy.intercept(
{ {
method: 'GET', method: 'GET',
url: `${accountsUrl}/oauth/v2/authorize/callback*`, url: `${issuerUrl}/authorize/callback*`,
times: 1, times: 1,
}, },
(req) => { (req) => {
@ -100,7 +102,7 @@ export function login(
cy.intercept( cy.intercept(
{ {
method: 'GET', method: 'GET',
url: `${accountsUrl}/oauth/v2/authorize*`, url: `${issuerUrl}/authorize*`,
times: 1, times: 1,
}, },
(req) => { (req) => {
@ -111,7 +113,7 @@ export function login(
); );
} }
cy.visit(`${consoleUrl}/loginname`, { retryOnNetworkFailure: true }); cy.visit(`${loginUrl}`, { retryOnNetworkFailure: true });
otherZitadelIdpInstance && cy.wait('@login'); otherZitadelIdpInstance && cy.wait('@login');
onUsernameScreen ? onUsernameScreen() : null; onUsernameScreen ? onUsernameScreen() : null;
@ -127,7 +129,7 @@ export function login(
otherZitadelIdpInstance && cy.wait('@callback'); otherZitadelIdpInstance && cy.wait('@callback');
cy.location('pathname', { timeout: 5 * 1000 }).should('eq', '/'); cy.location('pathname', { timeout: 5 * 1000 }).should('eq', '/ui/console/');
}, },
{ {
validate: () => { validate: () => {
@ -141,14 +143,14 @@ export function login(
); );
} }
export function username(withoutDomain: string, project?: string): string { export function username(withoutDomain: string, org?: string): string {
return `${withoutDomain}@${project ? `${project}.` : ''}${host(Cypress.env('apiUrl')).replace('api.', '')}`; return `${withoutDomain}@${org}.${host(Cypress.env('baseUrl'))}`;
} }
function credentials(user: User, pw?: string) { function credentials(user: User, pw?: string) {
const isAdmin = user == User.IAMAdminUser; // const isAdmin = user == User.IAMAdminUser;
return { return {
username: username(isAdmin ? user : `${user}_user_name`, isAdmin ? 'caos-ag' : Cypress.env('org')), username: username(`${user}_user_name`, Cypress.env('org')),
password: pw ? pw : Cypress.env(`${user}_password`), password: pw ? pw : Cypress.env(`${user}_password`),
}; };
} }

View File

@ -7,8 +7,8 @@
"build": "ng build", "build": "ng build",
"prodbuild": "ng build --configuration production --base-href=/ui/console/", "prodbuild": "ng build --configuration production --base-href=/ui/console/",
"lint": "ng lint && stylelint './src/**/*.scss' --syntax scss", "lint": "ng lint && stylelint './src/**/*.scss' --syntax scss",
"e2e": "./cypress.sh run e2e.env", "e2e": "./cypress.sh run ../e2e/local.env",
"e2e:open": "./cypress.sh open e2e.env" "e2e:open": "./cypress.sh open ../e2e/local.env"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {

View File

@ -6,10 +6,7 @@ ZITADEL_E2E_ORGPROJECTCREATORPW=Password1!
ZITADEL_E2E_PASSWORDCOMPLEXITYUSERPW=Password1! ZITADEL_E2E_PASSWORDCOMPLEXITYUSERPW=Password1!
ZITADEL_E2E_LOGINPOLICYUSERPW=Password1! ZITADEL_E2E_LOGINPOLICYUSERPW=Password1!
ZITADEL_E2E_MACHINEKEYPATH="${projectRoot}/.keys/e2e.json" ZITADEL_E2E_MACHINEKEYPATH="${projectRoot}/.keys/e2e.json"
ZITADEL_E2E_CONSOLEURL="http://localhost:8080/ui/console/" ZITADEL_E2E_BASEURL="http://localhost:8080"
ZITADEL_E2E_APIURL="http://localhost:8080"
ZITADEL_E2E_ACCOUNTSURL="http://localhost:8080"
ZITADEL_E2E_ISSUERURL="http://localhost:8080/oauth/v2"
ZITADEL_E2E_OTHERZITADELIDPINSTANCE=false ZITADEL_E2E_OTHERZITADELIDPINSTANCE=false
ZITADEL_E2E_ZITADELPROJECTRESOURCEID="bignumber-$(echo -n $(${projectRoot}/e2e/docker-compose.sh exec --no-TTY db cockroach sql --database zitadel --insecure --execute "select aggregate_id from eventstore.events where event_type = 'project.added' and event_data = '{\"name\": \"ZITADEL\"}';" --format tsv) | cut -d " " -f 2)" ZITADEL_E2E_ZITADELPROJECTRESOURCEID="bignumber-$(echo -n $(${projectRoot}/e2e/docker-compose.sh exec --no-TTY db cockroach sql --database zitadel --insecure --execute "select aggregate_id from eventstore.events where event_type = 'project.added' and event_data = '{\"name\": \"ZITADEL\"}';" --format tsv) | cut -d " " -f 2)"
ZITADEL_E2E_INSTANCEID="$(echo -n $(${projectRoot}/e2e/docker-compose.sh exec --no-TTY db cockroach sql --database zitadel --insecure --execute "select aggregate_id from eventstore.events where event_type = 'instance.added' and event_data = '{\"name\": \"Localhost\"}';" --format tsv) | cut -d " " -f 2)" ZITADEL_E2E_INSTANCEID="$(echo -n $(${projectRoot}/e2e/docker-compose.sh exec --no-TTY db cockroach sql --database zitadel --insecure --execute "select aggregate_id from eventstore.events where event_type = 'instance.added' and event_data = '{\"name\": \"Localhost\"}';" --format tsv) | cut -d " " -f 2)"