mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:17:32 +00:00
test(e2e): test authorizations (#4342)
* add specs that cover the b2b demo * update cypress * test handling manager roles * use shared mocha contexts * use beforeEach instead of before * improve readability * improve application test * remove static waits * remove old awaitDesired * test owned project authorizations * simplify ensure.ts * test granted projects authz * disable prevSubject for shouldNotExist * await non-existence, then expect no error * update dependencies * fix tests from scratch * fix settings tests from scratch * Apply suggestions from code review Co-authored-by: Max Peintner <max@caos.ch> * Implement code review suggestions * use spread operator * settings properties must match * add check settings object * revert spread operator Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
@@ -1,17 +1,23 @@
|
||||
import { login, User } from 'support/login/users';
|
||||
import { API } from './types';
|
||||
|
||||
export interface apiCallProperties {
|
||||
authHeader: string;
|
||||
mgntBaseURL: string;
|
||||
adminBaseURL: string;
|
||||
}
|
||||
const authHeaderKey = 'Authorization',
|
||||
orgIdHeaderKey = 'x-zitadel-orgid';
|
||||
|
||||
export function apiAuth(): Cypress.Chainable<apiCallProperties> {
|
||||
export function apiAuth(): Cypress.Chainable<API> {
|
||||
return login(User.IAMAdminUser, 'Password1!', false, true).then((token) => {
|
||||
return <apiCallProperties>{
|
||||
authHeader: `Bearer ${token}`,
|
||||
mgntBaseURL: `${Cypress.env('BACKEND_URL')}/management/v1/`,
|
||||
adminBaseURL: `${Cypress.env('BACKEND_URL')}/admin/v1/`,
|
||||
return <API>{
|
||||
token: token,
|
||||
mgmtBaseURL: `${Cypress.env('BACKEND_URL')}/management/v1`,
|
||||
adminBaseURL: `${Cypress.env('BACKEND_URL')}/admin/v1`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function requestHeaders(api: API, orgId?: number): object {
|
||||
const headers = { [authHeaderKey]: `Bearer ${api.token}` };
|
||||
if (orgId) {
|
||||
headers[orgIdHeaderKey] = orgId;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
@@ -1,196 +1,123 @@
|
||||
import { apiCallProperties } from './apiauth';
|
||||
import { requestHeaders } from './apiauth';
|
||||
import { findFromList as mapFromList, searchSomething } from './search';
|
||||
import { API, Entity, SearchResult } from './types';
|
||||
|
||||
export function ensureSomethingExists(
|
||||
api: apiCallProperties,
|
||||
export function ensureItemExists(
|
||||
api: API,
|
||||
searchPath: string,
|
||||
find: (entity: any) => boolean,
|
||||
findInList: (entity: Entity) => boolean,
|
||||
createPath: string,
|
||||
body: any,
|
||||
body: Entity,
|
||||
orgId?: number,
|
||||
newItemIdField: string = 'id',
|
||||
searchItemIdField?: string,
|
||||
): Cypress.Chainable<number> {
|
||||
return searchSomething(api, searchPath, find)
|
||||
.then((sRes) => {
|
||||
if (sRes.entity) {
|
||||
return cy.wrap({
|
||||
id: sRes.entity.id,
|
||||
initialSequence: 0,
|
||||
});
|
||||
}
|
||||
return cy
|
||||
.request({
|
||||
method: 'POST',
|
||||
url: `${api.mgntBaseURL}${createPath}`,
|
||||
headers: {
|
||||
Authorization: api.authHeader,
|
||||
},
|
||||
body: body,
|
||||
failOnStatusCode: false,
|
||||
followRedirect: false,
|
||||
})
|
||||
.then((cRes) => {
|
||||
expect(cRes.status).to.equal(200);
|
||||
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);
|
||||
});
|
||||
return ensureSomething(
|
||||
api,
|
||||
() => searchSomething(api, searchPath, 'POST', mapFromList(findInList, searchItemIdField), orgId),
|
||||
() => createPath,
|
||||
'POST',
|
||||
body,
|
||||
(entity) => !!entity,
|
||||
(body) => body[newItemIdField],
|
||||
orgId,
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureSomethingIsSet(
|
||||
api: apiCallProperties,
|
||||
path: string,
|
||||
find: (entity: any) => SearchResult,
|
||||
createPath: string,
|
||||
body: any,
|
||||
): Cypress.Chainable<number> {
|
||||
return getSomething(api, path, find)
|
||||
.then((sRes) => {
|
||||
if (sRes.entity) {
|
||||
return cy.wrap({
|
||||
id: sRes.entity.id,
|
||||
initialSequence: 0,
|
||||
});
|
||||
}
|
||||
return cy
|
||||
.request({
|
||||
method: 'PUT',
|
||||
url: createPath,
|
||||
headers: {
|
||||
Authorization: api.authHeader,
|
||||
},
|
||||
body: body,
|
||||
failOnStatusCode: false,
|
||||
followRedirect: false,
|
||||
})
|
||||
.then((cRes) => {
|
||||
expect(cRes.status).to.equal(200);
|
||||
return {
|
||||
id: cRes.body.id,
|
||||
initialSequence: sRes.sequence,
|
||||
};
|
||||
});
|
||||
})
|
||||
.then((data) => {
|
||||
awaitDesiredById(90, (entity) => !!entity, data.initialSequence, api, path, find);
|
||||
return cy.wrap<number>(data.id);
|
||||
});
|
||||
}
|
||||
|
||||
export function ensureSomethingDoesntExist(
|
||||
api: apiCallProperties,
|
||||
export function ensureItemDoesntExist(
|
||||
api: API,
|
||||
searchPath: string,
|
||||
find: (entity: any) => boolean,
|
||||
deletePath: (entity: any) => string,
|
||||
findInList: (entity: Entity) => boolean,
|
||||
deletePath: (entity: Entity) => string,
|
||||
orgId?: number,
|
||||
): Cypress.Chainable<null> {
|
||||
return searchSomething(api, searchPath, find)
|
||||
.then((sRes) => {
|
||||
if (!sRes.entity) {
|
||||
return cy.wrap(0);
|
||||
}
|
||||
return cy
|
||||
.request({
|
||||
method: 'DELETE',
|
||||
url: `${api.mgntBaseURL}${deletePath(sRes.entity)}`,
|
||||
headers: {
|
||||
Authorization: api.authHeader,
|
||||
},
|
||||
failOnStatusCode: false,
|
||||
})
|
||||
.then((dRes) => {
|
||||
expect(dRes.status).to.equal(200);
|
||||
return sRes.sequence;
|
||||
});
|
||||
})
|
||||
.then((initialSequence) => {
|
||||
awaitDesired(90, (entity) => !entity, initialSequence, api, searchPath, find);
|
||||
return null;
|
||||
});
|
||||
return ensureSomething(
|
||||
api,
|
||||
() => searchSomething(api, searchPath, 'POST', mapFromList(findInList), orgId),
|
||||
deletePath,
|
||||
'DELETE',
|
||||
null,
|
||||
(entity) => !entity,
|
||||
).then(() => null);
|
||||
}
|
||||
|
||||
type SearchResult = {
|
||||
entity: any;
|
||||
sequence: number;
|
||||
};
|
||||
|
||||
function searchSomething(
|
||||
api: apiCallProperties,
|
||||
searchPath: string,
|
||||
find: (entity: any) => boolean,
|
||||
): Cypress.Chainable<SearchResult> {
|
||||
return cy
|
||||
.request({
|
||||
method: 'POST',
|
||||
url: `${api.mgntBaseURL}${searchPath}`,
|
||||
headers: {
|
||||
Authorization: api.authHeader,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
return {
|
||||
entity: res.body.result?.find(find) || null,
|
||||
sequence: res.body.details.processedSequence,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getSomething(
|
||||
api: apiCallProperties,
|
||||
searchPath: string,
|
||||
find: (entity: any) => SearchResult,
|
||||
): Cypress.Chainable<SearchResult> {
|
||||
return cy
|
||||
.request({
|
||||
method: 'GET',
|
||||
url: searchPath,
|
||||
headers: {
|
||||
Authorization: api.authHeader,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
return find(res.body);
|
||||
});
|
||||
export function ensureSetting(
|
||||
api: API,
|
||||
path: string,
|
||||
mapResult: (entity: any) => SearchResult,
|
||||
createPath: string,
|
||||
body: any,
|
||||
orgId?: number,
|
||||
): Cypress.Chainable<number> {
|
||||
return ensureSomething(
|
||||
api,
|
||||
() => searchSomething(api, path, 'GET', mapResult, orgId),
|
||||
() => createPath,
|
||||
'PUT',
|
||||
body,
|
||||
(entity) => !!entity,
|
||||
(body) => body?.settings?.id,
|
||||
);
|
||||
}
|
||||
|
||||
function awaitDesired(
|
||||
trials: number,
|
||||
expectEntity: (entity: any) => boolean,
|
||||
initialSequence: number,
|
||||
api: apiCallProperties,
|
||||
searchPath: string,
|
||||
find: (entity: any) => boolean,
|
||||
expectEntity: (entity: Entity) => boolean,
|
||||
search: () => Cypress.Chainable<SearchResult>,
|
||||
initialSequence?: number,
|
||||
) {
|
||||
searchSomething(api, searchPath, find).then((resp) => {
|
||||
search().then((resp) => {
|
||||
const foundExpectedEntity = expectEntity(resp.entity);
|
||||
const foundExpectedSequence = resp.sequence > initialSequence;
|
||||
const foundExpectedSequence = !initialSequence || resp.sequence >= initialSequence;
|
||||
|
||||
if (!foundExpectedEntity || !foundExpectedSequence) {
|
||||
expect(trials, `trying ${trials} more times`).to.be.greaterThan(0);
|
||||
cy.wait(1000);
|
||||
awaitDesired(trials - 1, expectEntity, initialSequence, api, searchPath, find);
|
||||
awaitDesired(trials - 1, expectEntity, search, initialSequence);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function awaitDesiredById(
|
||||
trials: number,
|
||||
expectEntity: (entity: any) => boolean,
|
||||
initialSequence: number,
|
||||
api: apiCallProperties,
|
||||
path: string,
|
||||
find: (entity: any) => SearchResult,
|
||||
) {
|
||||
getSomething(api, path, find).then((resp) => {
|
||||
const foundExpectedEntity = expectEntity(resp.entity);
|
||||
const foundExpectedSequence = resp.sequence > initialSequence;
|
||||
|
||||
if (!foundExpectedEntity || !foundExpectedSequence) {
|
||||
expect(trials, `trying ${trials} more times`).to.be.greaterThan(0);
|
||||
cy.wait(1000);
|
||||
awaitDesiredById(trials - 1, expectEntity, initialSequence, api, path, find);
|
||||
}
|
||||
});
|
||||
interface EnsuredResult {
|
||||
id: number;
|
||||
sequence: number;
|
||||
}
|
||||
|
||||
export function ensureSomething(
|
||||
api: API,
|
||||
search: () => Cypress.Chainable<SearchResult>,
|
||||
apiPath: (entity: Entity) => string,
|
||||
ensureMethod: string,
|
||||
body: Entity,
|
||||
expectEntity: (entity: Entity) => boolean,
|
||||
mapId?: (body: any) => number,
|
||||
orgId?: number,
|
||||
): Cypress.Chainable<number> {
|
||||
return search()
|
||||
.then<EnsuredResult>((sRes) => {
|
||||
if (expectEntity(sRes.entity)) {
|
||||
return cy.wrap({ id: sRes.id, sequence: sRes.sequence });
|
||||
}
|
||||
|
||||
return cy
|
||||
.request({
|
||||
method: ensureMethod,
|
||||
url: apiPath(sRes.entity),
|
||||
headers: requestHeaders(api, orgId),
|
||||
body: body,
|
||||
failOnStatusCode: false,
|
||||
followRedirect: false,
|
||||
})
|
||||
.then((cRes) => {
|
||||
expect(cRes.status).to.equal(200);
|
||||
return {
|
||||
id: mapId ? mapId(cRes.body) : undefined,
|
||||
sequence: sRes.sequence,
|
||||
};
|
||||
});
|
||||
})
|
||||
.then((data) => {
|
||||
awaitDesired(90, expectEntity, search, data.sequence);
|
||||
return cy.wrap<number>(data.id);
|
||||
});
|
||||
}
|
||||
|
22
e2e/cypress/support/api/grants.ts
Normal file
22
e2e/cypress/support/api/grants.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ensureItemExists } from './ensure';
|
||||
import { getOrgUnderTest } from './orgs';
|
||||
import { API } from './types';
|
||||
|
||||
export function ensureProjectGrantExists(
|
||||
api: API,
|
||||
foreignOrgId: number,
|
||||
foreignProjectId: number,
|
||||
): Cypress.Chainable<number> {
|
||||
return getOrgUnderTest(api).then((orgUnderTest) => {
|
||||
return ensureItemExists(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/projectgrants/_search`,
|
||||
(grant: any) => grant.grantedOrgId == orgUnderTest && grant.projectId == foreignProjectId,
|
||||
`${api.mgmtBaseURL}/projects/${foreignProjectId}/grants`,
|
||||
{ granted_org_id: orgUnderTest },
|
||||
foreignOrgId,
|
||||
'grantId',
|
||||
'grantId',
|
||||
);
|
||||
});
|
||||
}
|
76
e2e/cypress/support/api/members.ts
Normal file
76
e2e/cypress/support/api/members.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { ensureItemDoesntExist, ensureItemExists } from './ensure';
|
||||
import { findFromList, searchSomething } from './search';
|
||||
import { API } from './types';
|
||||
|
||||
export function ensureHumanIsNotOrgMember(api: API, username: string): Cypress.Chainable<number> {
|
||||
return ensureItemDoesntExist(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/orgs/me/members/_search`,
|
||||
(member: any) => (<string>member.preferredLoginName).startsWith(username),
|
||||
(member) => `${api.mgmtBaseURL}/orgs/me/members/${member.userId}`,
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureHumanIsOrgMember(api: API, username: string, roles: string[]): Cypress.Chainable<number> {
|
||||
return searchSomething(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/users/_search`,
|
||||
'POST',
|
||||
findFromList((user) => {
|
||||
return user.userName == username;
|
||||
}),
|
||||
).then((user) => {
|
||||
return ensureItemExists(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/orgs/me/members/_search`,
|
||||
(member: any) => member.userId == user.entity.id,
|
||||
`${api.mgmtBaseURL}/orgs/me/members`,
|
||||
{
|
||||
userId: user.entity.id,
|
||||
roles: roles,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function ensureHumanIsNotProjectMember(
|
||||
api: API,
|
||||
projectId: string,
|
||||
username: string,
|
||||
grantId?: number,
|
||||
): Cypress.Chainable<number> {
|
||||
return ensureItemDoesntExist(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${grantId ? `grants/${grantId}/` : ''}members/_search`,
|
||||
(member: any) => (<string>member.preferredLoginName).startsWith(username),
|
||||
(member) => `${api.mgmtBaseURL}/projects/${projectId}${grantId ? `grants/${grantId}/` : ''}/members/${member.userId}`,
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureHumanIsProjectMember(
|
||||
api: API,
|
||||
projectId: string,
|
||||
username: string,
|
||||
roles: string[],
|
||||
grantId?: number,
|
||||
): Cypress.Chainable<number> {
|
||||
return searchSomething(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/users/_search`,
|
||||
'POST',
|
||||
findFromList((user) => {
|
||||
return user.userName == username;
|
||||
}),
|
||||
).then((user) => {
|
||||
return ensureItemExists(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${grantId ? `grants/${grantId}/` : ''}members/_search`,
|
||||
(member: any) => member.userId == user.entity.id,
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${grantId ? `grants/${grantId}/` : ''}members`,
|
||||
{
|
||||
userId: user.entity.id,
|
||||
roles: roles,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
@@ -1,32 +1,35 @@
|
||||
import { apiCallProperties } from './apiauth';
|
||||
import { ensureSomethingIsSet } from './ensure';
|
||||
import { ensureSetting } from './ensure';
|
||||
import { API } from './types';
|
||||
|
||||
export function ensureOIDCSettingsSet(
|
||||
api: apiCallProperties,
|
||||
accessTokenLifetime,
|
||||
idTokenLifetime,
|
||||
refreshTokenExpiration,
|
||||
api: API,
|
||||
accessTokenLifetime: number,
|
||||
idTokenLifetime: number,
|
||||
refreshTokenExpiration: number,
|
||||
refreshTokenIdleExpiration: number,
|
||||
): Cypress.Chainable<number> {
|
||||
return ensureSomethingIsSet(
|
||||
return ensureSetting(
|
||||
api,
|
||||
`${api.adminBaseURL}settings/oidc`,
|
||||
(settings: any) => {
|
||||
let entity = null;
|
||||
if (
|
||||
settings.settings?.accessTokenLifetime === hoursToDuration(accessTokenLifetime) &&
|
||||
settings.settings?.idTokenLifetime === hoursToDuration(idTokenLifetime) &&
|
||||
settings.settings?.refreshTokenExpiration === daysToDuration(refreshTokenExpiration) &&
|
||||
settings.settings?.refreshTokenIdleExpiration === daysToDuration(refreshTokenIdleExpiration)
|
||||
) {
|
||||
entity = settings.settings;
|
||||
}
|
||||
return {
|
||||
entity: entity,
|
||||
sequence: settings.settings?.details?.sequence,
|
||||
`${api.adminBaseURL}/settings/oidc`,
|
||||
(body: any) => {
|
||||
const result = {
|
||||
sequence: body.settings?.details?.sequence,
|
||||
id: body.settings.id,
|
||||
entity: null,
|
||||
};
|
||||
|
||||
if (
|
||||
body.settings &&
|
||||
body.settings.accessTokenLifetime === hoursToDuration(accessTokenLifetime) &&
|
||||
body.settings.idTokenLifetime === hoursToDuration(idTokenLifetime) &&
|
||||
body.settings.refreshTokenExpiration === daysToDuration(refreshTokenExpiration) &&
|
||||
body.settings.refreshTokenIdleExpiration === daysToDuration(refreshTokenIdleExpiration)
|
||||
) {
|
||||
return { ...result, entity: body.settings };
|
||||
}
|
||||
return result;
|
||||
},
|
||||
`${api.adminBaseURL}settings/oidc`,
|
||||
`${api.adminBaseURL}/settings/oidc`,
|
||||
{
|
||||
accessTokenLifetime: hoursToDuration(accessTokenLifetime),
|
||||
idTokenLifetime: hoursToDuration(idTokenLifetime),
|
||||
|
30
e2e/cypress/support/api/orgs.ts
Normal file
30
e2e/cypress/support/api/orgs.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { ensureSomething } from './ensure';
|
||||
import { searchSomething } from './search';
|
||||
import { API } from './types';
|
||||
import { host } from '../login/users';
|
||||
|
||||
export function ensureOrgExists(api: API, name: string): Cypress.Chainable<number> {
|
||||
return ensureSomething(
|
||||
api,
|
||||
() =>
|
||||
searchSomething(
|
||||
api,
|
||||
encodeURI(`${api.mgmtBaseURL}/global/orgs/_by_domain?domain=${name}.${host(Cypress.config('baseUrl'))}`),
|
||||
'GET',
|
||||
(res) => {
|
||||
return { entity: res.org, id: res.org?.id, sequence: res.org?.details?.sequence };
|
||||
},
|
||||
),
|
||||
() => `${api.mgmtBaseURL}/orgs`,
|
||||
'POST',
|
||||
{ name: name },
|
||||
(org: any) => org?.name === name,
|
||||
(res) => res.id,
|
||||
);
|
||||
}
|
||||
|
||||
export function getOrgUnderTest(api: API): Cypress.Chainable<number> {
|
||||
return searchSomething(api, `${api.mgmtBaseURL}/orgs/me`, 'GET', (res) => {
|
||||
return { entity: res.org, id: res.org.id, sequence: res.org.details.sequence };
|
||||
}).then((res) => res.entity.id);
|
||||
}
|
@@ -1,16 +1,15 @@
|
||||
import { apiCallProperties } from './apiauth';
|
||||
import { requestHeaders } from './apiauth';
|
||||
import { API } from './types';
|
||||
|
||||
export enum Policy {
|
||||
Label = 'label',
|
||||
}
|
||||
|
||||
export function resetPolicy(api: apiCallProperties, policy: Policy) {
|
||||
export function resetPolicy(api: API, policy: Policy) {
|
||||
cy.request({
|
||||
method: 'DELETE',
|
||||
url: `${api.mgntBaseURL}/policies/${policy}`,
|
||||
headers: {
|
||||
Authorization: api.authHeader,
|
||||
},
|
||||
url: `${api.mgmtBaseURL}/policies/${policy}`,
|
||||
headers: requestHeaders(api),
|
||||
}).then((res) => {
|
||||
expect(res.status).to.equal(200);
|
||||
return null;
|
||||
|
@@ -1,18 +1,24 @@
|
||||
import { apiCallProperties } from './apiauth';
|
||||
import { ensureSomethingDoesntExist, ensureSomethingExists } from './ensure';
|
||||
import { ensureItemDoesntExist, ensureItemExists } from './ensure';
|
||||
import { API } from './types';
|
||||
|
||||
export function ensureProjectExists(api: apiCallProperties, projectName: string): Cypress.Chainable<number> {
|
||||
return ensureSomethingExists(api, `projects/_search`, (project: any) => project.name === projectName, 'projects', {
|
||||
name: projectName,
|
||||
});
|
||||
export function ensureProjectExists(api: API, projectName: string, orgId?: number): Cypress.Chainable<number> {
|
||||
return ensureItemExists(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/projects/_search`,
|
||||
(project: any) => project.name === projectName,
|
||||
`${api.mgmtBaseURL}/projects`,
|
||||
{ name: projectName },
|
||||
orgId,
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureProjectDoesntExist(api: apiCallProperties, projectName: string): Cypress.Chainable<null> {
|
||||
return ensureSomethingDoesntExist(
|
||||
export function ensureProjectDoesntExist(api: API, projectName: string, orgId?: number): Cypress.Chainable<null> {
|
||||
return ensureItemDoesntExist(
|
||||
api,
|
||||
`projects/_search`,
|
||||
`${api.mgmtBaseURL}/projects/_search`,
|
||||
(project: any) => project.name === projectName,
|
||||
(project) => `projects/${project.id}`,
|
||||
(project) => `${api.mgmtBaseURL}/projects/${project.id}`,
|
||||
orgId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -25,33 +31,28 @@ export const Roles = new ResourceType('roles', 'key', 'key');
|
||||
//export const Grants = new ResourceType('apps', 'name')
|
||||
|
||||
export function ensureProjectResourceDoesntExist(
|
||||
api: apiCallProperties,
|
||||
api: API,
|
||||
projectId: number,
|
||||
resourceType: ResourceType,
|
||||
resourceName: string,
|
||||
orgId?: number,
|
||||
): Cypress.Chainable<null> {
|
||||
return ensureSomethingDoesntExist(
|
||||
return ensureItemDoesntExist(
|
||||
api,
|
||||
`projects/${projectId}/${resourceType.resourcePath}/_search`,
|
||||
(resource: any) => {
|
||||
return resource[resourceType.compareProperty] === resourceName;
|
||||
},
|
||||
(resource) => {
|
||||
return `projects/${projectId}/${resourceType.resourcePath}/${resource[resourceType.identifierProperty]}`;
|
||||
},
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${resourceType.resourcePath}/_search`,
|
||||
(resource: any) => resource[resourceType.compareProperty] === resourceName,
|
||||
(resource) =>
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${resourceType.resourcePath}/${resource[resourceType.identifierProperty]}`,
|
||||
orgId,
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureApplicationExists(
|
||||
api: apiCallProperties,
|
||||
projectId: number,
|
||||
appName: string,
|
||||
): Cypress.Chainable<number> {
|
||||
return ensureSomethingExists(
|
||||
export function ensureApplicationExists(api: API, projectId: number, appName: string): Cypress.Chainable<number> {
|
||||
return ensureItemExists(
|
||||
api,
|
||||
`projects/${projectId}/${Apps.resourcePath}/_search`,
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${Apps.resourcePath}/_search`,
|
||||
(resource: any) => resource.name === appName,
|
||||
`projects/${projectId}/${Apps.resourcePath}/oidc`,
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${Apps.resourcePath}/oidc`,
|
||||
{
|
||||
name: appName,
|
||||
redirectUris: ['https://e2eredirecturl.org'],
|
||||
@@ -59,11 +60,6 @@ export function ensureApplicationExists(
|
||||
grantTypes: ['OIDC_GRANT_TYPE_AUTHORIZATION_CODE'],
|
||||
authMethodType: 'OIDC_AUTH_METHOD_TYPE_NONE',
|
||||
postLogoutRedirectUris: ['https://e2elogoutredirecturl.org'],
|
||||
/* "clientId": "129383004379407963@e2eprojectpermission",
|
||||
"clockSkew": "0s",
|
||||
"allowedOrigins": [
|
||||
"https://testurl.org"
|
||||
]*/
|
||||
},
|
||||
);
|
||||
}
|
||||
|
32
e2e/cypress/support/api/search.ts
Normal file
32
e2e/cypress/support/api/search.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { requestHeaders } from './apiauth';
|
||||
import { API, Entity, SearchResult } from './types';
|
||||
|
||||
export function searchSomething(
|
||||
api: API,
|
||||
searchPath: string,
|
||||
method: string,
|
||||
mapResult: (body: any) => SearchResult,
|
||||
orgId?: number,
|
||||
): Cypress.Chainable<SearchResult> {
|
||||
return cy
|
||||
.request({
|
||||
method: method,
|
||||
url: searchPath,
|
||||
headers: requestHeaders(api, orgId),
|
||||
failOnStatusCode: method == 'POST',
|
||||
})
|
||||
.then((res) => {
|
||||
return mapResult(res.body);
|
||||
});
|
||||
}
|
||||
|
||||
export function findFromList(find: (entity: Entity) => boolean, idField: string = 'id'): (body: any) => SearchResult {
|
||||
return (b) => {
|
||||
const entity = b.result?.find(find);
|
||||
return {
|
||||
entity: entity,
|
||||
sequence: parseInt(<string>b.details.processedSequence),
|
||||
id: entity?.[idField],
|
||||
};
|
||||
};
|
||||
}
|
14
e2e/cypress/support/api/types.ts
Normal file
14
e2e/cypress/support/api/types.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export interface API {
|
||||
token: string;
|
||||
mgmtBaseURL: string;
|
||||
adminBaseURL: string;
|
||||
}
|
||||
|
||||
export type SearchResult = {
|
||||
entity: Entity | null;
|
||||
sequence: number;
|
||||
id: number;
|
||||
};
|
||||
|
||||
// Entity is an object but not a function
|
||||
export type Entity = { [k: string]: any } & ({ bind?: never } | { call?: never });
|
@@ -1,35 +1,51 @@
|
||||
import { apiCallProperties } from './apiauth';
|
||||
import { ensureSomethingDoesntExist, ensureSomethingExists } from './ensure';
|
||||
import { ensureItemDoesntExist, ensureItemExists } from './ensure';
|
||||
import { API } from './types';
|
||||
|
||||
export function ensureHumanUserExists(api: apiCallProperties, username: string): Cypress.Chainable<number> {
|
||||
return ensureSomethingExists(api, 'users/_search', (user: any) => user.userName === username, 'users/human', {
|
||||
user_name: username,
|
||||
profile: {
|
||||
first_name: 'e2efirstName',
|
||||
last_name: 'e2elastName',
|
||||
},
|
||||
email: {
|
||||
email: 'e2e@email.ch',
|
||||
},
|
||||
phone: {
|
||||
phone: '+41 123456789',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function ensureMachineUserExists(api: apiCallProperties, username: string): Cypress.Chainable<number> {
|
||||
return ensureSomethingExists(api, 'users/_search', (user: any) => user.userName === username, 'users/machine', {
|
||||
user_name: username,
|
||||
name: 'e2emachinename',
|
||||
description: 'e2emachinedescription',
|
||||
});
|
||||
}
|
||||
|
||||
export function ensureUserDoesntExist(api: apiCallProperties, username: string): Cypress.Chainable<null> {
|
||||
return ensureSomethingDoesntExist(
|
||||
export function ensureHumanUserExists(api: API, username: string): Cypress.Chainable<number> {
|
||||
return ensureItemExists(
|
||||
api,
|
||||
'users/_search',
|
||||
`${api.mgmtBaseURL}/users/_search`,
|
||||
(user: any) => user.userName === username,
|
||||
(user) => `users/${user.id}`,
|
||||
`${api.mgmtBaseURL}/users/human`,
|
||||
{
|
||||
user_name: username,
|
||||
profile: {
|
||||
first_name: 'e2efirstName',
|
||||
last_name: 'e2elastName',
|
||||
},
|
||||
email: {
|
||||
email: 'e2e@email.ch',
|
||||
},
|
||||
phone: {
|
||||
phone: '+41 123456789',
|
||||
},
|
||||
},
|
||||
undefined,
|
||||
'userId',
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureMachineUserExists(api: API, username: string): Cypress.Chainable<number> {
|
||||
return ensureItemExists(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/users/_search`,
|
||||
(user: any) => user.userName === username,
|
||||
`${api.mgmtBaseURL}/users/machine`,
|
||||
{
|
||||
user_name: username,
|
||||
name: 'e2emachinename',
|
||||
description: 'e2emachinedescription',
|
||||
},
|
||||
undefined,
|
||||
'userId',
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureUserDoesntExist(api: API, username: string): Cypress.Chainable<null> {
|
||||
return ensureItemDoesntExist(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/users/_search`,
|
||||
(user: any) => user.userName === username,
|
||||
(user) => `${api.mgmtBaseURL}/users/${user.id}`,
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user