Skip to content

Commit

Permalink
Merge c26e6b2 into a18eae1
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Apr 30, 2022
2 parents a18eae1 + c26e6b2 commit 928c418
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 26 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/code-ql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
pull_request:
paths-ignore:
- "**.md"
- "docs"
schedule:
- cron: "0 14 * * 4"

Expand All @@ -26,15 +27,15 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
Expand All @@ -48,4 +49,4 @@ jobs:
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
174 changes: 171 additions & 3 deletions docs/docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ module.exports = {

</Tab>
<Tab label="Mocha + chai">

Run these commands to install mocha chai and sinon:

```bash
Expand Down Expand Up @@ -130,7 +130,8 @@ process.on("unhandledRejection", (reason, p) => {

### Usage

Ts.ED provides @@PlatformTest@@ to create a new context to inject your Services, Controllers, Middlewares, etc... registered with annotations like @@Injectable@@.
Ts.ED provides @@PlatformTest@@ to create a new context to inject your Services, Controllers, Middlewares, etc...
registered with annotations like @@Injectable@@.

The process to test any components is the same thing:

Expand Down Expand Up @@ -243,10 +244,177 @@ If you use the PlatformTest, you'll probably get an error when you'll run the un
Platform type is not specified. Have you added at least `import @tsed/platform-express` (or equivalent) on your Server.ts ?
```

To solve it, just add the `import @tsed/platform-express` on your `Server.ts`. PlatformTest need this import to know on which Platform
To solve it, just add the `import @tsed/platform-express` on your `Server.ts`. PlatformTest need this import to know on
which Platform
your server must be executed for integration test.
:::

### Stub a service method

When you're testing your API, you have sometimes to stub a method of a service.

Here is an example to do that:

<Tabs class="-code">
<Tab label="Jest">

```typescript
import {PlatformTest} from "@tsed/common";
import SuperTest from "supertest";
import {Server} from "../../Server";
import {Chapter} from "../../entity/Chapter";

const entity = new Chapter();
Object.assign(entity, {
id: 2,
bookId: 4,
timestamp: 1650996201,
name: "First Day At Work"
});

describe("ChapterController", () => {
let request: SuperTest.SuperTest<SuperTest.Test>;

beforeAll(PlatformTest.bootstrap(Server));
beforeAll(async () => {
const service = PlatformTest.get(ChapterService);

jest.spyOn(service, "findChapters").mockResolvedValue([entity]);
request = SuperTest(PlatformTest.callback());
});
afterAll(PlatformTest.reset);

describe("GET /rest/chapter", () => {
it("Get All Chapters", async () => {
const response = await request.get("/rest/chapter").expect(200);
expect(typeof response.body).toEqual("object");
});
});
});
```

</Tab>
<Tab label="Mocha">

```typescript
import {PlatformTest} from "@tsed/common";
import SuperTest from "supertest";
import Sinon from "sinon";
import {Server} from "../../Server";
import {Chapter} from "../../entity/Chapter";

const entity = new Chapter();
Object.assign(entity, {
id: 2,
bookId: 4,
timestamp: 1650996201,
name: "First Day At Work"
});

const sandbox = Sinon.createSandbox();
describe("ChapterController", () => {
let request: SuperTest.SuperTest<SuperTest.Test>;

beforeAll(PlatformTest.bootstrap(Server));
beforeAll(async () => {
const service = PlatformTest.get(ChapterService);

sandbox.stub(service, "findChapters").resolves([entity]);
request = SuperTest(PlatformTest.callback());
});
afterAll(PlatformTest.reset);
afterAll(() => sandbox.restore());

describe("GET /rest/chapter", () => {
it("Get All Chapters", async () => {
const response = await request.get("/rest/chapter").expect(200);
expect(typeof response.body).to.eq("object");
});
});
});
```

</Tab>
</Tabs>

### Stub a middleware method <Badge text="6.114.3+" />

When you're testing your API, you have sometimes to stub middleware to disable authentication for example.

Here is an example to do that:

<Tabs class="-code">
<Tab label="Jest">

```typescript
import {PlatformTest} from "@tsed/common";
import SuperTest from "supertest";
import {TestMongooseContext} from "@tsed/testing-mongoose";
import {HelloWorldController} from "./HelloWorldController";
import {Server} from "../../Server";
import {AuthMiddleware} from "../../middlewares/auth.middleware";

describe("HelloWorldController", () => {
let request: SuperTest.SuperTest<SuperTest.Test>;

beforeAll(TestMongooseContext.bootstrap(Server));
beforeAll(() => {
request = SuperTest(PlatformTest.callback());

const authMiddleware = PlatformTest.get<AuthMiddleware>(AuthMiddleware);
jest.spyOn(authMiddleware, "use").mockResolvedValue(true);
});
beforeEach(() => {
jest.clearAllMocks();
});
afterAll(TestMongooseContext.reset);

it("should return value", async () => {
const response = await request.get("/rest/hello-world").expect(200);
expect(response.text).toEqual("hello");
});
});
```

</Tab>
<Tab label="Mocha">

```typescript
import {PlatformTest} from "@tsed/common";
import SuperTest from "supertest";
import Sinon from "sinon";
import {HelloWorldController} from "./HelloWorldController";
import {Server} from "../../Server";
import {TestMongooseContext} from "@tsed/testing-mongoose";
import {AuthMiddleware} from "../../middlewares/auth.middleware";

const sandbox = Sinon.createSandbox();

describe("HelloWorldController", () => {
let request: SuperTest.SuperTest<SuperTest.Test>;

beforeAll(TestMongooseContext.bootstrap(Server));
beforeAll(() => {
request = SuperTest(PlatformTest.callback());

const authMiddleware = PlatformTest.get<AuthMiddleware>(AuthMiddleware);
sandbox.stub(authMiddleware, "use").resolves(true);
});
beforeEach(() => {
sandbox.restore();
});
afterAll(TestMongooseContext.reset);

it("should return value", async () => {
const response = await request.get("/rest/hello-world").expect(200);
expect(response.text).to.equal("hello");
});
});
```

</Tab>
</Tabs>

### Testing session

To install session with Ts.ED see our [tutorial](/tutorials/session.md).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,18 @@ export class PlatformParams {

if (!provider || !provider.scope || provider.scope === ProviderScope.SINGLETON) {
const instance = await this.injector.invoke<any>(token);
const handler = instance[propertyKey!].bind(instance);

return async (scope) => {
const args = await getArguments(scope);

return handler(...args, scope.$ctx);
return instance[propertyKey!].call(instance, ...args, scope.$ctx);
};
}

return async (scope) => {
const [instance, args] = await Promise.all([this.injector.invoke<any>(token, scope.$ctx.container), getArguments(scope)]);

const handler = instance[propertyKey!].bind(instance);

return handler(...args, scope.$ctx);
return instance[propertyKey].call(instance, ...args, scope.$ctx);
};
}
}
26 changes: 23 additions & 3 deletions packages/specs/schema/src/utils/getJsonPathParameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,41 @@ function getVariable(subpath: string) {
};
}

function cleanKey(key: string) {
let inCapture = 0;

return key
.split("")
.filter((c) => {
if (c === "(") {
inCapture++;
}

const result = inCapture === 0;

if (c === ")") {
inCapture--;
}

return result;
})
.join("");
}

/**
* @ignore
*/
export function getJsonPathParameters(base: string, path: string | RegExp | (string | RegExp)[] = ""): {path: string; parameters: any[]}[] {
if (path instanceof RegExp) {
path = path.toString().replace(/^\//, "").replace(/\/$/, "").replace(/\\/, "");
path = path.toString().replace(/^\//g, "").replace(/\/$/g, "").replace(/\\/g, "");
}

const params: any[] = [];
const paths: any[] = [];
let isOptional = false;
let current = "";

`${base}${path}`
.replace(/\((.*)\)/gi, "")
cleanKey(`${base}${path}`)
.split("/")
.filter((o) => !!o)
.map((key) => {
Expand Down
11 changes: 2 additions & 9 deletions packages/third-parties/components-scan/src/importFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,8 @@ export async function importFiles(patterns: string | string[], exclude: string[]
for (const file of files.sort((a, b) => (a < b ? -1 : 1))) {
if (!file.endsWith(".d.ts")) {
// prevent .d.ts import if the global pattern isn't correctly configured
try {
const exports = await importPackage(file);
Object.keys(exports).forEach((key) => symbols.push(exports[key]));
} catch (er) {
// istanbul ignore next
console.error(er);
// istanbul ignore next
process.exit(1);
}
const exports = await importPackage(file);
Object.keys(exports).forEach((key) => symbols.push(exports[key]));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ function sanitize(customConditional: Function) {
let content = fn.join("=>");

if (!signature.includes("{")) {
const reg = `${signature.trim()}\.`;

content = content.replace(new RegExp(reg, "gi"), "");
content = content.replace(new RegExp(`${signature.trim()}.`, "gi"), "");
}

return `show = ${content.trim()}`;
Expand Down

0 comments on commit 928c418

Please sign in to comment.