diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index b326b00..fb2518e 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -76,3 +76,5 @@ jobs: name: ${{ steps.prebuild.outputs.version }} Release body: ${{ steps.prebuild.outputs.version }} target: ${{ github.ref }} + draft: true + prerelease: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 47b00dd..5b27cfc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -66,6 +66,8 @@ jobs: name: ${{ steps.prebuild.outputs.version }} Release body: ${{ steps.prebuild.outputs.version }} target: ${{ github.ref }} + draft: true + prerelease: false - name: upload id: upload uses: ./.github/actions/upload-asset diff --git a/package.json b/package.json index b471a4a..a67127c 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,21 @@ { "name": "typescript-react-electron-starter", - "version": "0.0.2", + "version": "0.0.3", "description": "TypeScript React Electron Starter", "main": "app/main.js", "scripts": { - "clear": "gulp --cwd . clear && rimraf ./node_modules ./app ./dist ./coverage ./it/screenshots ./package-lock.json ./gulpfile.js ./gulpfile.js.map ./.github/actions/gulpfile.js ./.github/actions/gulpfile.js.map", + "clear": "gulp --cwd . clear && rimraf ./node_modules ./app ./dist ./coverage ./coverage-it ./it/screenshots ./package-lock.json ./gulpfile.js ./gulpfile.js.map ./.github/actions/gulpfile.js ./.github/actions/gulpfile.js.map", "postinstall": "tsc -p ./", "actions": "gulp --gulpfile ./.github/actions/gulpfile.js --cwd .", - "prebuild": "rimraf ./app ./dist ./coverage ./it/screenshots", + "prebuild": "rimraf ./app ./dist ./coverage ./coverage-it ./it/screenshots", "build": "gulp --cwd .", "predist": "rimraf ./app ./dist", "dist": "gulp --cwd . dist", "start": "electron ./", "pretest": "rimraf ./coverage", "test": "jest --testEnvironment enzyme --coverage --coverageDirectory ../coverage --rootDir ./src", - "preit": "rimraf ./it/screenshots", - "it": "jest --rootDir ./it" + "preit": "rimraf ./coverage-it ./it/screenshots", + "it": "jest --runInBand --coverage --coverageDirectory ../coverage-it --rootDir ./it" }, "repository": { "type": "git", @@ -30,8 +30,10 @@ "typescript" ], "jest": { + "collectCoverage": true, "collectCoverageFrom": [ "**/*.{ts,tsx}", + "**/*.{js,jsx}", "!**/node_modules/**" ], "moduleFileExtensions": [ diff --git a/src/__snapshots__/application.spec.tsx.snap b/src/__snapshots__/application.spec.tsx.snap index b37fa81..514f176 100644 --- a/src/__snapshots__/application.spec.tsx.snap +++ b/src/__snapshots__/application.spec.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Application Application snapshot 1`] = ` +exports[`Application snapshot 1`] = `
diff --git a/src/application.spec.tsx b/src/application.spec.tsx index db0b8c9..cffb864 100644 --- a/src/application.spec.tsx +++ b/src/application.spec.tsx @@ -1,3 +1,4 @@ +import { mount, ReactWrapper } from "enzyme"; import * as React from "react"; import * as renderer from "react-test-renderer"; @@ -7,16 +8,43 @@ import { RendererService } from "./rendererService"; describe("Application", (): void => { - const service: RendererService = new RendererService(undefined as any, undefined as any); + const pingMock: jest.Mock = jest.fn(); + const RendererServiceMock: jest.Mock + = jest.fn().mockImplementation((props: TestSubject.IApplicationProperties, context?: any) => { + return { + ping: pingMock, + }; + }); + + const service: RendererService = new RendererServiceMock(); - it("Application export exists", (): void => { + beforeEach((): void => { + RendererServiceMock.mockClear(); + }); + it("export exists", (): void => { expect(TestSubject.Application).toBeDefined(); }); - it("Application snapshot", (): void => { + it("snapshot", (): void => { const snapshot: renderer.ReactTestRenderer = renderer.create(); snapshot.toJSON(); expect(snapshot).toMatchSnapshot(); }); + it("header", (): void => { + const testSubject: ReactWrapper + = mount(); + + expect(testSubject.find("h1").text()).toBe("Application loaded"); + }); + + it("button clicked", (): void => { + const testSubject: ReactWrapper + = mount(); + + expect(pingMock).toBeCalledTimes(0); + testSubject.find("Button").find("button").simulate("click"); + expect(pingMock).toBeCalledTimes(1); + }); + }); diff --git a/src/application.tsx b/src/application.tsx index 532c9dc..b2c5f90 100644 --- a/src/application.tsx +++ b/src/application.tsx @@ -4,7 +4,7 @@ import { RendererService } from "./rendererService"; import { Button } from "./button"; -interface IApplicationProperties { +export interface IApplicationProperties { service: RendererService; } diff --git a/src/mainService.spec.tsx b/src/mainService.spec.tsx index fb1148a..0c7b597 100644 --- a/src/mainService.spec.tsx +++ b/src/mainService.spec.tsx @@ -2,31 +2,109 @@ import { mount, ReactWrapper } from "enzyme"; import * as React from "react"; import * as renderer from "react-test-renderer"; +import { IIPCMessage, IPCChannel, IPCMessageType } from "./ipc"; + import * as TestSubject from "./mainService"; describe("MainService", (): void => { - it("MainService export exists", (): void => { + const sendMock: jest.Mock = jest.fn(); + const onMock: jest.Mock = jest.fn(); + let eventCallback: (event: Electron.IpcMainEvent | Electron.IpcRendererEvent, ...args: any[]) => void; + + const handler: (channel: IPCChannel, + callback: (event: Electron.IpcMainEvent | Electron.IpcRendererEvent, ...args: any[]) => void) + => void = (channel: IPCChannel, callback: (event: Electron.IpcMainEvent | Electron.IpcRendererEvent, + ...args: any[]) => void): void => { + eventCallback = callback; + onMock(channel); + }; + + const ipcMock: any = { + on: handler, + send: sendMock, + }; + + beforeEach((): void => { + onMock.mockClear(); + }); + + it("export exists", (): void => { expect(TestSubject.MainService).toBeDefined(); }); it("register", (): void => { - const ipc: any = { - on: jest.fn(), + const testSubject: TestSubject.MainService = new TestSubject.MainService(ipcMock, "main-channel"); + testSubject.register(); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + }); + + it("invalid event", (): void => { + const testSubject: TestSubject.MainService = new TestSubject.MainService(ipcMock, "main-channel"); + const eventSenderSendMock: jest.Mock = jest.fn(); + const event: any = { + sender: { + send: eventSenderSendMock, + }, }; + testSubject.register(); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + eventCallback(event, 1, 2, 3); + expect(event.sender.send).toHaveBeenCalledTimes(0); + }); - const testSubject: TestSubject.MainService = new TestSubject.MainService(ipc, "main-channel"); + it("ping event", (): void => { + const testSubject: TestSubject.MainService = new TestSubject.MainService(ipcMock, "main-channel"); + const eventSenderSendMock: jest.Mock = jest.fn(); + const event: any = { + sender: { + send: eventSenderSendMock, + }, + }; testSubject.register(); - expect(ipc.on).toHaveBeenCalledTimes(1); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + eventCallback(event, { + data: "test", + timestamp: new Date(), + type: "ping", + } as IIPCMessage); + expect(event.sender.send).toHaveBeenCalledTimes(2); }); - it("callback", (): void => { - const ipc: any = { - on: jest.fn(), + + it("pong event", (): void => { + const testSubject: TestSubject.MainService = new TestSubject.MainService(ipcMock, "main-channel"); + const eventSenderSendMock: jest.Mock = jest.fn(); + const event: any = { + sender: { + send: eventSenderSendMock, + }, }; + testSubject.register(); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + eventCallback(event, { + data: "test", + timestamp: new Date(), + type: "pong", + } as IIPCMessage); + expect(event.sender.send).toHaveBeenCalledTimes(0); + }); - const testSubject: TestSubject.MainService = new TestSubject.MainService(ipc, "main-channel"); + it("unknown event", (): void => { + const testSubject: TestSubject.MainService = new TestSubject.MainService(ipcMock, "main-channel"); + const eventSenderSendMock: jest.Mock = jest.fn(); + const event: any = { + sender: { + send: eventSenderSendMock, + }, + }; testSubject.register(); - expect(ipc.on).toHaveBeenCalledTimes(1); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + eventCallback(event, { + data: "test", + timestamp: new Date(), + type: "test", + } as any); + expect(event.sender.send).toHaveBeenCalledTimes(0); }); }); diff --git a/src/rendererService.spec.tsx b/src/rendererService.spec.tsx index 7ce07e5..c804a93 100644 --- a/src/rendererService.spec.tsx +++ b/src/rendererService.spec.tsx @@ -2,41 +2,112 @@ import { mount, ReactWrapper } from "enzyme"; import * as React from "react"; import * as renderer from "react-test-renderer"; +import { IIPCMessage, IPCChannel, IPCMessageType } from "./ipc"; + import * as TestSubject from "./rendererService"; + describe("RendererService", (): void => { - it("RendererService export exists", (): void => { + const sendMock: jest.Mock = jest.fn(); + const onMock: jest.Mock = jest.fn(); + let eventCallback: (event: Electron.IpcMainEvent | Electron.IpcRendererEvent, ...args: any[]) => void; + + const handler: (channel: IPCChannel, + callback: (event: Electron.IpcMainEvent | Electron.IpcRendererEvent, ...args: any[]) => void) + => void = (channel: IPCChannel, callback: (event: Electron.IpcMainEvent | Electron.IpcRendererEvent, + ...args: any[]) => void): void => { + eventCallback = callback; + onMock(channel); + }; + + const ipcMock: any = { + on: handler, + send: sendMock, + }; + + beforeEach((): void => { + onMock.mockClear(); + }); + + it("export exists", (): void => { expect(TestSubject.RendererService).toBeDefined(); }); it("ping", (): void => { - const ipc: any = { - send: jest.fn(), - }; - - const testSubject: TestSubject.RendererService = new TestSubject.RendererService(ipc, "main-channel"); + const testSubject: TestSubject.RendererService = new TestSubject.RendererService(ipcMock, "main-channel"); testSubject.ping(); - expect(ipc.send).toHaveBeenCalledTimes(1); + expect(ipcMock.send).toHaveBeenCalledTimes(1); }); it("register", (): void => { - const ipc: any = { - on: jest.fn(), + const testSubject: TestSubject.RendererService = new TestSubject.RendererService(ipcMock, "main-channel"); + testSubject.register(); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + }); + + + it("event", (): void => { + const testSubject: TestSubject.RendererService = new TestSubject.RendererService(ipcMock, "main-channel"); + const eventSenderSendMock: jest.Mock = jest.fn(); + const event: any = { + sender: { + send: eventSenderSendMock, + }, }; + testSubject.register(); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + eventCallback(event, "test"); + }); - const testSubject: TestSubject.RendererService = new TestSubject.RendererService(ipc, "main-channel"); + it("invalid event", (): void => { + const testSubject: TestSubject.RendererService = new TestSubject.RendererService(ipcMock, "main-channel"); + const eventSenderSendMock: jest.Mock = jest.fn(); + const event: any = { + sender: { + send: eventSenderSendMock, + }, + }; testSubject.register(); - expect(ipc.on).toHaveBeenCalledTimes(1); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + eventCallback(event, "test", 1); + eventCallback(event); }); - it("callback", (): void => { - const ipc: any = { - on: jest.fn(), + it("ping event", (): void => { + const testSubject: TestSubject.RendererService = new TestSubject.RendererService(ipcMock, "main-channel"); + const eventSenderSendMock: jest.Mock = jest.fn(); + const event: any = { + sender: { + send: eventSenderSendMock, + }, }; + testSubject.register(); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + eventCallback(event, { + data: "test", + timestamp: new Date(), + type: "ping", + } as IIPCMessage); + expect(event.sender.send).toHaveBeenCalledTimes(1); + }); - const testSubject: TestSubject.RendererService = new TestSubject.RendererService(ipc, "main-channel"); + + it("pong event", (): void => { + const testSubject: TestSubject.RendererService = new TestSubject.RendererService(ipcMock, "main-channel"); + const eventSenderSendMock: jest.Mock = jest.fn(); + const event: any = { + sender: { + send: eventSenderSendMock, + }, + }; testSubject.register(); - expect(ipc.on).toHaveBeenCalledTimes(1); + expect(onMock).toHaveBeenNthCalledWith(1, "main-channel"); + eventCallback(event, { + data: "test", + timestamp: new Date(), + type: "pong", + } as IIPCMessage); + expect(event.sender.send).toHaveBeenCalledTimes(0); }); }); diff --git a/src/rendererService.ts b/src/rendererService.ts index 3fd8b8a..3d789d8 100644 --- a/src/rendererService.ts +++ b/src/rendererService.ts @@ -13,7 +13,6 @@ export class RendererService extends IpcService { protected handleMessage(event: Electron.IpcRendererEvent, message: IIPCMessage): void { switch (message.type) { case "ping": - console.log(message); this.send(event.sender, this.channel, "pong", message.data); break; case "pong":