cumulocity-cypress
Version:
Cypress commands for Cumulocity IoT
474 lines (473 loc) • 19 kB
JavaScript
import { getShellVersionFromEnv, getSystemVersionFromEnv, normalizedC8yclientArguments, throwError, } from "../utils";
import { toSemverVersion } from "../../shared/versioning";
const { _ } = Cypress;
Cypress.Commands.add("createUser", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth, userOptions, roles, applications, clientOptions] = $args;
const consoleProps = {
args: args || null,
auth: auth || null,
userOptions: userOptions || null,
roles: roles || null,
applications: applications || null,
clientOptions: clientOptions || null,
};
const logger = Cypress.log({
autoEnd: false,
name: "createUser",
message: userOptions?.userName || null,
consoleProps: () => consoleProps,
});
logger.end();
if (!userOptions) {
logger.end();
throw new Error("Missing argument. Requiring user options argument.");
}
// use cy.wrap(auth) to pass auth from createUser to c8yclient
// note auth might be undefined which means c8yclient will choose auth.
return cy
.wrap(auth, { log: false })
.c8yclient((c) => c.user.create(userOptions), clientOptions)
.then((userResponse) => {
const userId = userResponse.body.id;
consoleProps.userId = userId;
if (roles && !_.isEmpty(roles)) {
consoleProps.roles = roles;
cy.wrap(roles, { log: false }).each((role) => {
cy.wrap(auth, { log: false }).c8yclient([
(c) => c.core.fetch("/user/" + c.core.tenant + "/groupByName/" + role),
(c, groupResponse) => {
const childId = userResponse?.body?.self;
const groupId = groupResponse?.body?.id;
if (!childId || !groupId) {
throwError(`Failed to add user ${childId} to group ${childId}.`);
}
return c.userGroup.addUserToGroup(groupId, childId);
},
], clientOptions);
});
}
if (applications && !_.isEmpty(applications)) {
consoleProps.applications = applications;
cy.wrap(applications, { log: false }).each((appName) => {
cy.wrap(auth, { log: false }).c8yclient([
(c) => c.core.fetch("/application/applicationsByName/" + appName, {
headers: {
accept: "application/vnd.com.nsn.cumulocity.applicationcollection+json",
},
}),
(c, applicationResponse) => {
const applications = applicationResponse?.body?.applications ||
applicationResponse?.body;
if (!applications || !_.isArrayLike(applications)) {
throwError(`Application ${appName} not found. No or empty response.`);
}
const apps = applications.map((a) => {
if (_.isString(a)) {
return {
type: "HOSTED",
id: a,
};
}
else if (_.isObjectLike(a) && a.id) {
return _.pick(_.defaults(a, { type: "HOSTED" }), [
"id",
"type",
]);
}
return undefined;
});
return c.user.update({ id: userId, applications: apps });
},
], clientOptions);
});
}
logger.end();
return cy.wrap(userResponse);
});
});
Cypress.Commands.add("deleteUser", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth, user, clientOptions] = $args;
const options = { ...clientOptions, ...{ failOnStatusCode: false } };
const username = _.isObjectLike(user) ? user.userName : user;
const consoleProps = {
auth: auth || null,
clientOptions: options || null,
user: user || null,
username: username || null,
};
const logger = Cypress.log({
autoEnd: false,
name: "deleteUser",
consoleProps: () => consoleProps,
});
if (!username || !_.isString(username)) {
logger.end();
throwError("Missing argument. deleteUser() requires IUser object with userName or username string argument.");
}
return cy
.wrap(auth, { log: false })
.c8yclient((c) => c.user.delete(username), options)
.then((deleteResponse) => {
logger.end();
expect(deleteResponse.status).to.be.oneOf([204, 404]);
return cy.wrap(deleteResponse);
});
});
Cypress.Commands.add("clearUserRoles", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth, user, clientOptions] = $args;
const options = { ...clientOptions };
const userIdentifier = _.isObjectLike(user) && user.userName ? user.userName : user;
const consoleProps = {
args: args || null,
auth: auth || null,
clientOptions: options,
user: user || null,
};
const logger = Cypress.log({
autoEnd: false,
name: "clearUserRoles",
message: userIdentifier,
consoleProps: () => consoleProps,
});
if (!user || (_.isObjectLike(user) && !user.userName)) {
logger.end();
return throwError("Missing argument. Requiring IUser object with userName or username argument.");
}
return cy
.wrap(auth, { log: false })
.c8yclient((client) => client.user.detail(userIdentifier), options)
.then((response) => {
const assignedRoles = response.body.groups.references;
consoleProps.assignedRoles = assignedRoles || null;
if (!assignedRoles || assignedRoles.length === 0) {
return cy.wrap(auth, { log: false });
}
cy.wrap(assignedRoles, { log: false }).each((assingedRole) => {
cy.wrap(auth, { log: false }).c8yclient((client) => client.userGroup.removeUserFromGroup(assingedRole.group.id, userIdentifier), options);
});
logger.end();
return cy.wrap(auth, { log: false });
});
});
Cypress.Commands.add("createGlobalRole", {
prevSubject: "optional",
}, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth, globalRole, rolesToAssign, clientOptions] = $args;
const roleOptions = _.isObjectLike(globalRole)
? globalRole
: { name: globalRole };
const consoleProps = {
args: args || null,
auth: auth || null,
rolesToAssign: rolesToAssign || null,
roleOptions: roleOptions || null,
clientOptions: clientOptions || null,
};
const logger = Cypress.log({
autoEnd: false,
name: "createGlobalRole",
message: roleOptions.name ?? "",
consoleProps: () => consoleProps,
});
if (!_.isString(roleOptions.name) || _.isEmpty(roleOptions.name)) {
logger.end();
throwError("Missing argument. Requiring a name for the global role.");
}
return cy
.wrap(auth, { log: false })
.c8yclient((client) => client.userGroup.create(roleOptions), clientOptions)
.then((createResponse) => {
const userGroup = createResponse.body;
consoleProps.role = userGroup;
const userGroupId = userGroup.id;
if (!userGroupId) {
logger.end();
throwError("Failed to create global role. UserGroup id is missing.");
}
return cy
.wrap(auth, { log: false })
.c8yclient((client) => client.userRole.list({ pageSize: 2000, withTotalPages: false }), clientOptions)
.then((listResponse) => {
const listRoles = listResponse.body.roles;
consoleProps.existingRoles = listRoles || null;
const matches = [];
if (!listRoles || listRoles.length === 0) {
logger.end();
throwError("Failed to load roles. No roles found.");
}
for (const r of listRoles) {
if (rolesToAssign?.find((item) => item === r.id || item === r.name) != null) {
matches.push(r);
}
}
if (matches.length < rolesToAssign.length) {
logger.end();
throwError(`Failed to assign one of provided userRoles to ${roleOptions.name}. User role not found.`);
}
cy.wrap(auth, { log: false }).c8yclient((c) => matches
?.filter((item) => item.self != null)
.map((match) => c.userGroup.addRoleToGroup(userGroupId, match.self)), clientOptions);
})
.then(() => {
logger.end();
return cy.wrap(userGroup);
});
});
});
Cypress.Commands.add("deleteGlobalRoles", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth, roleNames, clientOptions] = $args;
const consoleProps = {
args: args || null,
auth: auth || null,
roleNames: roleNames || null,
clientOptions: clientOptions || null,
};
const logger = Cypress.log({
autoEnd: false,
name: "deleteGlobalRoles",
consoleProps: () => consoleProps,
});
if (!roleNames || !_.isArray(roleNames) || _.isEmpty(roleNames)) {
logger.end();
throwError("Missing argument. Requiring an array of role names.");
}
return cy
.wrap(auth, { log: false })
.c8yclient((c) => c.userGroup.list({ pageSize: 2000 }), clientOptions)
.then((listResponse) => {
const groups = listResponse.body.groups;
if (!groups || groups.length === 0) {
logger.end();
throwError("Failed to load userGroups. No groups found.");
}
return cy
.wrap(auth, { log: false })
.c8yclient((c) => groups
.filter((g) => roleNames.includes(g.name) && g.id != null)
.map((g) => c.userGroup.delete(g.id)), { ...clientOptions, ...{ failOnStatusCode: false } })
.then((response) => {
for (const res of response) {
expect(res.status).to.be.oneOf([204, 404]);
}
logger.end();
return cy.wrap(auth, { log: false });
});
});
});
Cypress.Commands.add("assignUserRoles", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth, user, roles, clientOptions] = $args;
const options = { ...clientOptions };
const consoleProps = {
args: args || null,
auth: auth || null,
user: user || null,
roles: roles || null,
clientOptions: options,
};
const userIdentifier = _.isObjectLike(user) && user?.userName ? user?.userName : user;
const logger = Cypress.log({
autoEnd: false,
name: "assignUserRoles",
message: userIdentifier,
consoleProps: () => consoleProps,
});
if (!user || (_.isObjectLike(user) && !user.userName)) {
logger.end();
return throwError("Missing argument. Requiring IUser object with userName or username argument.");
}
if (!roles || roles.length === 0) {
logger.end();
return throwError("Missing argument. Requiring an string array with roles.");
}
return cy
.wrap(auth, { log: false })
.c8yclient((client) => client.user.detail(userIdentifier), options)
.then((response) => {
cy.wrap(roles, { log: false }).each((role) => {
cy.wrap(auth, { log: false }).c8yclient([
(client) => client.core.fetch(`/user/${client.core.tenant}/groupByName/${role}`),
(client, groupResponse) => {
const childId = response?.body?.self;
const groupId = groupResponse?.body?.id;
if (childId == null || !groupId) {
logger.end();
throwError(`Failed to add user ${childId} to group ${childId}.`);
}
return client.userGroup.addUserToGroup(groupId, childId);
},
], options);
});
logger.end();
return cy.wrap(auth, { log: false });
});
});
Cypress.Commands.add("getCurrentTenant", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth, clientOptions] = $args;
const consoleProps = {
args: args || null,
auth: auth || null,
clientOptions: clientOptions || null,
};
Cypress.log({
name: "getCurrentTenant",
consoleProps: () => consoleProps,
});
cy.wrap(auth, { log: false }).c8yclient((c) => c.tenant.current(), clientOptions);
});
Cypress.Commands.add("getTenantId", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth] = $args;
const consoleProps = {
args: args || null,
auth: auth || null,
};
Cypress.log({
name: "getTenantId",
consoleProps: () => consoleProps,
});
if (Cypress.env("C8Y_TENANT") && !auth?.tenant) {
consoleProps.C8Y_TENANT = Cypress.env("C8Y_TENANT");
return cy.wrap(Cypress.env("C8Y_TENANT"));
}
// isMockingEnabled() also includes apply for matching of pacts with cy.c8ymatch
// for matching we might not want use tenant id from recordings
if (Cypress.c8ypact?.isEnabled() === true &&
Cypress.c8ypact.mode() === "mock") {
const tenant = Cypress.env("C8Y_TENANT") || Cypress.c8ypact.current?.info.tenant;
Cypress.env("C8Y_TENANT", tenant);
return cy.wrap(tenant);
}
cy.wrap(auth, { log: false })
.c8yclient()
.then((c) => {
Cypress.env("C8Y_TENANT", c.core.tenant);
cy.wrap(c.core.tenant);
});
});
Cypress.Commands.add("getSystemVersion", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth, clientOptions] = $args;
const consoleProps = {
args: args || null,
auth: auth || null,
clientOptions: clientOptions || null,
C8Y_SYSTEM_VERSION: Cypress.env("C8Y_SYSTEM_VERSION") || null,
C8Y_VERSION: Cypress.env("C8Y_VERSION") || null,
pactSystemVersion: Cypress.c8ypact.current?.info.version?.system || null,
};
Cypress.log({
name: "getSystemVersion",
consoleProps: () => consoleProps,
});
const systemVersion = getSystemVersionFromEnv();
if (systemVersion) {
consoleProps.Yields = systemVersion;
if (Cypress.env("C8Y_SYSTEM_VERSION") == null) {
Cypress.env("C8Y_SYSTEM_VERSION", systemVersion);
}
// set C8Y_VERSION for backward compatibility
if (Cypress.env("C8Y_VERSION") == null) {
Cypress.env("C8Y_VERSION", systemVersion);
}
return cy.wrap(systemVersion);
}
cy.wrap(auth, { log: false })
.c8yclient((c) => c.core.fetch("/tenant/system/options"), clientOptions)
.then((systemOptions) => {
const options = systemOptions.body && systemOptions.body.options;
consoleProps.systemOptions = options || null;
if (options) {
const versionOptions = options.filter((o) => o.category === "system" && o.key === "version");
if (!_.isEmpty(versionOptions)) {
const version = _.first(versionOptions).value;
consoleProps.Yields = version || null;
Cypress.env("C8Y_SYSTEM_VERSION", version);
Cypress.env("C8Y_VERSION", version);
return cy.wrap(version);
}
}
cy.wrap(undefined);
});
});
Cypress.Commands.add("getShellVersion", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
// eslint-disable-next-line prefer-const
let [auth, shellName, clientOptions] = $args;
if (_.isObjectLike(shellName)) {
shellName = undefined;
clientOptions = shellName;
}
const consoleProps = {
args: args || null,
auth: auth || null,
shellName: shellName || null,
clientOptions: clientOptions || null,
C8Y_SHELL_NAME: Cypress.env("C8Y_SHELL_NAME") || null,
};
Cypress.log({
name: "getShellVersion",
message: shellName || "cockpit",
consoleProps: () => consoleProps,
});
const version = getShellVersionFromEnv();
if (version) {
consoleProps.Yields = version;
return cy.wrap(version);
}
const myShell = shellName || Cypress.env("C8Y_SHELL_NAME") || "cockpit";
cy.wrap(auth, { log: false })
.c8yclient((c) => c.core.fetch(`/apps/${myShell}/cumulocity.json`), clientOptions)
.then((response) => {
consoleProps.response = response || null;
const shellVersion = toSemverVersion(response?.body?.version);
consoleProps.Yields = version || null;
Cypress.env("C8Y_SHELL_VERSION", shellVersion);
if (shellVersion != null && !Cypress.env("C8Y_SHELL_NAME")) {
Cypress.env("C8Y_SHELL_NAME", myShell);
}
cy.wrap(shellVersion);
});
});
Cypress.Commands.add("bootstrapDeviceCredentials", { prevSubject: "optional" }, (...args) => {
const $args = normalizedC8yclientArguments(args);
const [auth, id, clientOptions] = $args;
const consoleProps = {
args: args || null,
auth: auth || null,
clientOptions: clientOptions || null,
id: id || null,
};
Cypress.log({
name: "bootstrapDeviceCredentials",
id,
consoleProps: () => consoleProps,
});
const success = 201;
const failure = 404;
cy.wrap(auth, { log: false })
.c8yclientf((c) => c.core.fetch("/devicecontrol/deviceCredentials", {
method: "POST",
headers: {
accept: "application/vnd.com.nsn.cumulocity.devicecredentials+json",
},
body: JSON.stringify({ id }),
}), clientOptions)
.then((response) => {
expect(response.status).to.be.oneOf([success, failure]);
let result = undefined;
if (response.status === success &&
response.body &&
response.body.username) {
result = response.body;
}
consoleProps.Yielded = result;
cy.wrap(result);
});
});