Skip to content

Commit

Permalink
Merge pull request #85 from SoftwareAG/fix/84-fix-mount-c8yclient-dua…
Browse files Browse the repository at this point in the history
…l-package-hazard

#84: Fix loading plugin in Cypress with es2020
  • Loading branch information
thomaswinkler authored Apr 9, 2024
2 parents 446d3ef + 9203abd commit 91555ae
Show file tree
Hide file tree
Showing 14 changed files with 733 additions and 86 deletions.
566 changes: 566 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

20 changes: 18 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"name": "cumulocity-cypress",
"version": "0.3.2",
"description": "Cypress commands for Cumulocity IoT",
"main": "src/lib/commands/index.js",
"scripts": {
"start-server": "http-server test/cypress/app/ --silent --port 8080 --mimetypes test/custom_mime_types.types --ext json",
"test": "cross-env TZ=Europe/Berlin start-server-and-test start-server http://localhost:8080 test:run",
Expand All @@ -11,7 +10,8 @@
"debug": "cross-env CYPRESS_REMOTE_DEBUGGING_PORT=9222 cypress open --project test",
"clean": "rimraf dist/ && rimraf packages/pactrunner/dist/ && rimraf packages/pactrunner/.yalc && rimraf packages/pactrunner/yalc.lock",
"copy-files": "copyfiles --up 1 src/lib/**/*.*js src/lib/*.*js src/lib/**/*.d.ts dist/ && copyfiles README.md package.json dist/",
"build": "npm run clean && npm run copy-files && tsc -b -v src/lib/ && cd dist/ && npm run clean-package-json",
"build": "npm run clean && npm run copy-files && tsc -b -v src/lib && tsc -b -v src/plugin && npm run build:plugin && cd dist/ && npm run clean-package-json",
"build:plugin": "rollup -c rollup.config.mjs",
"yalc:runner": "npm run yalc:publish && cd packages/pactrunner && yalc add cumulocity-cypress",
"yalc:publish": "npm run clean && npm run build && cd dist/ && yalc publish && cd ..",
"clean-package-json": "npm pkg delete 'devDependencies' && npm pkg delete 'scripts'",
Expand All @@ -35,6 +35,17 @@
"workspaces": [
"packages/*"
],
"exports": {
"./plugin": {
"types": "./plugin/index.d.ts",
"default": "./plugin/index.js"
},
"./lib/commands/*": "./lib/commands/*",
"./lib/locale/*": "./lib/locale/*",
"./lib/pact/*": "./lib/pact/*",
"./shared/*": "./shared/*",
"./shared/c8ypact/*": "./shared/c8ypact/*"
},
"dependencies": {
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
Expand All @@ -49,6 +60,7 @@
"set-cookie-parser": "^2.6.0"
},
"devDependencies": {
"@rollup/plugin-json": "^6.1.0",
"@types/chai": "^4.3.4",
"@types/cookie-parser": "^1.4.6",
"@types/express": "^4.17.21",
Expand All @@ -67,6 +79,10 @@
"eslint-plugin-import": "^2.29.1",
"http-server": "^14.1.1",
"rimraf": "^5.0.1",
"rollup": "^4.14.1",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-dts": "^6.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"start-server-and-test": "^2.0.0",
"typescript": "^5.0.2",
"yalc": "^1.0.0-pre.53"
Expand Down
2 changes: 1 addition & 1 deletion packages/pactrunner/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineConfig } from "cypress";
import { configureC8yPlugin } from "cumulocity-cypress/lib/plugin";
import { configureC8yPlugin } from "cumulocity-cypress/plugin";
import { C8yPactDefaultFileAdapter } from "cumulocity-cypress/shared/c8ypact/fileadapter";

module.exports = defineConfig({
Expand Down
3 changes: 2 additions & 1 deletion packages/pactrunner/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"references": [
{ "path": "./../../src/shared" },
{ "path": "./../../src/lib" }
{ "path": "./../../src/lib" },
{ "path": "./../../src/plugin" }
]
}
31 changes: 31 additions & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import dts from "rollup-plugin-dts";
import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
// import typescript from "rollup-plugin-typescript2";
import json from "@rollup/plugin-json";

export default [
{
input: "dist/plugin/index.js",
output: [
{
name: "c8y",
file: "dist/plugin/index.js",
format: "umd",
sourcemap: true,
},
],
plugins: [
resolve({
only: ["./src/**"],
}),
commonjs(),
json(),
],
},
{
input: "dist/plugin/index.d.ts",
output: [{ file: "dist/plugin/index.d.ts", format: "es", sourcemap: true }],
plugins: [dts()],
},
];
19 changes: 0 additions & 19 deletions src/lib/commands/mount.d.ts

This file was deleted.

35 changes: 27 additions & 8 deletions src/lib/commands/mount.js → src/lib/commands/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,33 @@ import "./oauthlogin";
import { C8yPactFetchClient } from "../pact/fetchclient";
import { FetchClient } from "@c8y/client";
import { getAuthOptionsFromEnv, getBaseUrlFromEnv } from "../utils";
import { C8yAuthOptions } from "./auth";

declare global {
namespace Cypress {
interface Chainable {
/**
* Mount a Cumulocity Angular component. When mounting the component FetchClient
* provider will be C8yPactFetchClient to enable recording and mocking of
* requests and responses. Set base url with C8Y_BASEURL and pass authentication
* via cy.getAuth() or cy.useAuth().
*/
mount: typeof mount;
}
}
}

Cypress.Commands.add(
"mount",
// @ts-expect-error
{ prevSubject: "optional" },
(subject, component, options) => {
const consoleProps = {};
(subject: C8yAuthOptions, ...args) => {
const [component, options] = args;
const consoleProps: any = {};
const logger = Cypress.log({
autoEnd: false,
name: "mount",
// @ts-expect-error
message: isClass(component) ? component.name : component,
consoleProps: () => consoleProps,
});
Expand Down Expand Up @@ -45,7 +63,7 @@ Cypress.Commands.add(
throw error;
}

const registerFetchClient = (auth) => {
const registerFetchClient = (auth: C8yAuthOptions) => {
const fetchClient = new C8yPactFetchClient({
cypresspact: Cypress.c8ypact,
auth,
Expand All @@ -69,18 +87,19 @@ Cypress.Commands.add(

return (
Cypress.c8ypact.isRecordingEnabled() ||
Cypress.c8ypact.config.strictMocking === false
? cy.oauthLogin(auth, baseUrl)
: cy.wrap(auth)
).then((a) => {
Cypress.c8ypact.config?.strictMocking === false
? cy.oauthLogin(auth)
: cy.wrap<C8yAuthOptions>(auth)
).then((a: C8yAuthOptions) => {
registerFetchClient(a);
logger.end();

return mount(component, options);
});
}
);

function isClass(component) {
function isClass(component: any) {
return (
component &&
typeof component === "function" &&
Expand Down
33 changes: 0 additions & 33 deletions src/lib/commands/request.d.ts

This file was deleted.

77 changes: 63 additions & 14 deletions src/lib/commands/request.js → src/lib/commands/request.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,44 @@
import { getAuthOptionsFromEnv, normalizedArgumentsWithAuth } from "../utils";
const { _ } = Cypress;

declare global {
namespace Cypress {
interface Chainable {
/**
* Retry a request for a given number of max retries and delay. When test function
* `testFn` returns `true` stop retrying and continue.
*
* Use `retries` to pass number of retries and `retryDelay` to pass delay in milliseconds.
*
* @example
* cy.retryRequest(
* {
* method: "GET",
* url: "/service/apama-oeeapp/mon/ping",
* retries: Cypress.env("livenessRetries") || 5,
* retryDelay: Cypress.env("livenessRetryTimeout") || 10000,
* },
* (response) => {
* return response.status === 200;
* }
* );
*/
retryRequest<T = any>(
options: C8yRequestOptions,
testFn: (response: any) => boolean
): Chainable<Response<T>>;
}
interface Cypress {
cy: {
addCommand: (cmd: any) => void;
};
}
}

type RetryOptions = { retries: number; retryDelay: number };
type C8yRequestOptions = Partial<Cypress.RequestOptions> & RetryOptions;
}

const methods = [
"GET",
"POST",
Expand Down Expand Up @@ -30,14 +68,15 @@ const methods = [
"CONNECT",
];

function retryRequest(...args) {
function retryRequest(...args: any[]) {
const $args = normalizedArgumentsWithAuth(args);
if (!$args || $args.length !== 3) {
throw new Error(
"Missing argument. Requiring authentication, request options and test function."
);
}

// eslint-disable-next-line prefer-const -- auth is not reassigned
let [auth, options, testFn] = $args;
const orgOptions = _.cloneDeep(options);
const retryOptions = _.pick(options, ["retryDelay", "retries"]);
Expand Down Expand Up @@ -85,14 +124,16 @@ Cypress.Commands.add("retryRequest", { prevSubject: "optional" }, retryRequest);
// current solution uses a wrapper for the default request function that adds the authentication
// from environment.

const requestCommandWrapper = (wrappedFn) => {
return function (...args) {
const options = {};
const requestCommandWrapper = (
wrappedFn: Cypress.CommandFnWithOriginalFn<any>
) => {
return function (...args: any[]) {
const options: Partial<Cypress.RequestOptions> = {};

const originalFn = _.isFunction(args[0]) ? args[0] : undefined;
const $args = originalFn ? args.slice(1) : args;

const auth = getAuthOptionsFromEnv(...$args);
const auth = getAuthOptionsFromEnv.apply($args);

if (_.isObjectLike($args[0])) {
_.extend(options, $args[0]);
Expand All @@ -116,21 +157,29 @@ const requestCommandWrapper = (wrappedFn) => {
options.auth = _.omit(auth, "tenant");
}

const wrappedArgs = originalFn ? [args[0], options] : [options];
const wrappedArgs: any[] =
originalFn && args?.length > 0 ? [args[0], options] : [options];

// @ts-expect-error
return wrappedFn(...wrappedArgs);
};
};

const requestFn = Cypress.cy["request"];
Cypress.cy.addCommand({
name: "request",
fn: requestCommandWrapper(requestFn),
type: "parent",
prevSubject: null,
});
const requestFn = _.get(Cypress.cy, "request");
if (requestFn) {
Cypress.cy.addCommand({
name: "request",
fn: requestCommandWrapper(requestFn),
type: "parent",
prevSubject: null,
});
}

const overwriteFn = Cypress.Commands.overwrite;
Cypress.Commands.overwrite = (name, fn) => {
Cypress.Commands.overwrite = (
name: keyof Cypress.Chainable<any>,
fn: Cypress.CommandFnWithOriginalFn<any>
) => {
if (name === "request") {
overwriteFn(name, requestCommandWrapper(fn));
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/lib/plugin/index.ts → src/plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import * as fs from "fs";
import {
C8yPactFileAdapter,
C8yPactDefaultFileAdapter,
} from "../../shared/c8ypact/fileadapter";
import { C8yPact } from "../../shared/c8ypact/c8ypact";
import { C8yAuthOptions, oauthLogin } from "../../shared/c8yclient";
} from "../shared/c8ypact/fileadapter";
import { C8yPact } from "../shared/c8ypact/c8ypact";
import { C8yAuthOptions, oauthLogin } from "../shared/c8yclient";

export { C8yPactFileAdapter, C8yPactDefaultFileAdapter };

Expand Down
11 changes: 11 additions & 0 deletions src/plugin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": ".",
"outDir": "../../dist/plugin",
"lib": ["ES2020"],
"types": ["node", "cookie-parser", "cypress"],
"composite": true
},
"references": [{ "path": "./../shared" }]
}
2 changes: 1 addition & 1 deletion test/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineConfig } from "cypress";
import { configureC8yPlugin } from "../src/lib/plugin";
import { configureC8yPlugin } from "../src/plugin";

module.exports = defineConfig({
e2e: {
Expand Down
8 changes: 6 additions & 2 deletions test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"strict": true,
"module": "Node16",
"skipLibCheck": true,
"composite": true,
"composite": true
},
"references": [{ "path": "./../src/shared" }, { "path": "./../src/lib" }]
"references": [
{ "path": "./../src/shared" },
{ "path": "./../src/lib" },
{ "path": "./../src/plugin" }
]
}
Loading

0 comments on commit 91555ae

Please sign in to comment.