From b65c3b238bda34edac7e79b42eadfae4ef8e589b Mon Sep 17 00:00:00 2001 From: Jan Philip Schellenberg Date: Wed, 20 Jan 2021 01:28:02 +0100 Subject: [PATCH] Fix missing import error (closes #1164) (#1182) * fix(h5p-import): fix missing import error * fix(tracking): prevent tracking in CI environment --- client/src/state/H5PEditor/H5PEditorTypes.ts | 5 +- .../Notifications/NotificationsReducer.ts | 22 ++++- .../__tests__/NotificationsReducer.test.ts | 26 ++++- server/src/main.ts | 2 +- server/src/websocket.ts | 8 +- test/app.test.ts | 92 ++++++++++++++++++ test/broken.h5p | Bin 0 -> 4138 bytes test/launch.test.ts | 49 ---------- 8 files changed, 149 insertions(+), 55 deletions(-) create mode 100644 test/app.test.ts create mode 100644 test/broken.h5p delete mode 100644 test/launch.test.ts diff --git a/client/src/state/H5PEditor/H5PEditorTypes.ts b/client/src/state/H5PEditor/H5PEditorTypes.ts index 057d81e90..cda9f177e 100644 --- a/client/src/state/H5PEditor/H5PEditorTypes.ts +++ b/client/src/state/H5PEditor/H5PEditorTypes.ts @@ -99,7 +99,8 @@ export type H5PEditorActionTypes = | IH5PEditorSaveErrorAction | IH5PEditorExportActions | IH5PImportRequestAction - | IH5PImportSuccessAction; + | IH5PImportSuccessAction + | IH5PImportErrorAction; // @@ -333,10 +334,10 @@ export const H5P_IMPORT_REQUEST = 'H5P_IMPORT_REQUEST'; export const H5P_IMPORT_SUCCESS = 'H5P_IMPORT_SUCCESS'; export interface IH5PImportErrorAction { + error: { response: Superagent.Response }; payload: { tabId: string; path: string; - response: Superagent.Response; }; type: typeof H5P_IMPORT_ERROR; } diff --git a/client/src/state/Notifications/NotificationsReducer.ts b/client/src/state/Notifications/NotificationsReducer.ts index cd2af3f04..7fda58197 100644 --- a/client/src/state/Notifications/NotificationsReducer.ts +++ b/client/src/state/Notifications/NotificationsReducer.ts @@ -11,6 +11,7 @@ import { import { H5PEDITOR_SAVE_SUCCESS, H5PEDITOR_SAVE_ERROR, + H5P_IMPORT_ERROR, H5PEDITOR_EXPORT_SUCCESS, H5PEDITOR_EXPORT_ERROR, H5PEDITOR_ERROR, @@ -18,7 +19,8 @@ import { IH5PEditorSaveErrorAction, IH5PEditorExportErrorAction, IH5PEditorExportSuccessAction, - IH5PEditorError + IH5PEditorError, + IH5PImportErrorAction } from '../H5PEditor/H5PEditorTypes'; import shortid from 'shortid'; @@ -37,6 +39,7 @@ export default function notificationsReducer( | IH5PEditorExportErrorAction | IH5PEditorExportSuccessAction | IH5PEditorError + | IH5PImportErrorAction ): INotificationsState { switch (action.type) { case H5PEDITOR_ERROR: @@ -84,6 +87,23 @@ export default function notificationsReducer( ] }; + case H5P_IMPORT_ERROR: + return { + ...state, + notifications: [ + ...state.notifications, + { + key: shortid(), + message: + action.error.response.body.message || + 'notification.import.error', + options: { + variant: 'error' + } + } + ] + }; + case H5PEDITOR_EXPORT_SUCCESS: return { ...state, diff --git a/client/src/state/Notifications/__tests__/NotificationsReducer.test.ts b/client/src/state/Notifications/__tests__/NotificationsReducer.test.ts index a6671e295..c16411c88 100644 --- a/client/src/state/Notifications/__tests__/NotificationsReducer.test.ts +++ b/client/src/state/Notifications/__tests__/NotificationsReducer.test.ts @@ -10,7 +10,8 @@ import { H5PEDITOR_SAVE_SUCCESS, H5PEDITOR_SAVE_ERROR, H5PEDITOR_EXPORT_SUCCESS, - H5PEDITOR_EXPORT_ERROR + H5PEDITOR_EXPORT_ERROR, + H5P_IMPORT_ERROR } from '../../H5PEditor/H5PEditorTypes'; describe('initialState', () => { @@ -162,4 +163,27 @@ describe('Notifications', () => { expect(state.notifications[0].options.variant).toBe('error'); done(); }); + + it('shows a error notification on H5P_IMPORT_ERROR', (done) => { + const state = reducer( + { + notifications: [] + }, + { + error: { + response: { + body: { + message: 'test' + } + } + } as any, + payload: {} as any, + type: H5P_IMPORT_ERROR + } + ); + + expect(state.notifications.length).toBe(1); + expect(state.notifications[0].options.variant).toBe('error'); + done(); + }); }); diff --git a/server/src/main.ts b/server/src/main.ts index 27817176f..0dbf47a2a 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -31,7 +31,7 @@ process.on('uncaughtException', (error) => { // }); // } -if (process.env.NODE_ENV !== 'development') { +if (process.env.NODE_ENV !== 'development' && process.env.NODE_ENV !== 'CI') { nucleus.init('5e284c9a73aa9c0115e0d1d6'); nucleus.appStarted(); nucleus.setProps( diff --git a/server/src/websocket.ts b/server/src/websocket.ts index 2f6c19e61..89ff73814 100644 --- a/server/src/websocket.ts +++ b/server/src/websocket.ts @@ -9,8 +9,14 @@ const log = new Logger('websocket'); export default function (server: http.Server): SocketIO.Server { log.info('booting'); const io: SocketIO.Server = SocketIO(server); - io.on('connection', () => { + io.on('connection', (socket: SocketIO.Socket) => { log.info('new connection'); + + socket.on('dispatch', (action) => { + log.info(action); + + io.emit('action', action); + }); }); // io.on('error', (error) => { diff --git a/test/app.test.ts b/test/app.test.ts new file mode 100644 index 000000000..c4b5694cf --- /dev/null +++ b/test/app.test.ts @@ -0,0 +1,92 @@ +import path from 'path'; +import { Application } from 'spectron'; +import socketio from 'socket.io-client'; + +const PORT = 8090; + +describe('App', () => { + let app: Application; + beforeAll(() => { + app = new Application({ + env: { + USERDATA: path.join(__dirname, 'data'), + PORT: PORT, + NODE_ENV: 'CI' + }, + path: path.join( + __dirname, + '..', + 'node_modules', + '.bin', + 'electron' + ), + args: [path.join(__dirname, '..')] + }); + return app.start(); + }, 30000); + + afterAll(() => { + if (app && app.isRunning()) { + return app.stop(); + } + }); + + describe('launch', () => { + it('shows an initial window', async (done) => { + const count = await app.client.getWindowCount(); + expect(count).toBeGreaterThan(0); + done(); + }); + + it('shows the Lumi H5P Editor text', async (done) => { + const headline = await app.client.$('h1'); + const text = await headline.getText(); + + expect(text).toBe('Lumi H5P Editor'); + done(); + }); + + it('has the editor-startpage secondary button', async (done) => { + const button = await app.client.$( + '#editor-startpage-secondaryButton' + ); + + expect(button).toBeTruthy(); + done(); + }); + }); + + describe('Import H5P file', () => { + it('displays an error snackbar if the imported .h5p file is not valid', async (done) => { + const ws = socketio(`http://localhost:${PORT}`); + + ws.emit('dispatch', { + payload: { paths: [`${__dirname}/broken.h5p`] }, + type: 'OPEN_H5P' + }); + + const snackbar = await app.client.$('#notistack-snackbar'); + expect(await snackbar.getText()).toBe( + 'package-validation-failed:invalid-h5p-json-file' + ); + + ws.disconnect(); + + done(); + }); + + // it('imports a valid .h5p file', async (done) => { + // const ws = socketio(`http://localhost:${PORT}`); + + // ws.emit('dispatch', { + // payload: { paths: [`${__dirname}/valid.h5p`] }, + // type: 'OPEN_H5P' + // }); + + // setTimeout(() => { + // ws.disconnect(); + // done(); + // }, 10000); + // }); + }); +}); diff --git a/test/broken.h5p b/test/broken.h5p new file mode 100644 index 0000000000000000000000000000000000000000..70357aa0d4b4d349568c8fac035a3d4f26132658 GIT binary patch literal 4138 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 c@(=pH8 { - let app: Application; - beforeAll(() => { - app = new Application({ - env: { - USERDATA: path.join(__dirname, 'data') - }, - path: path.join( - __dirname, - '..', - 'node_modules', - '.bin', - 'electron' - ), - args: [path.join(__dirname, '..')] - }); - return app.start(); - }, 30000); - - afterAll(() => { - if (app && app.isRunning()) { - return app.stop(); - } - }); - - it('shows an initial window', async (done) => { - const count = await app.client.getWindowCount(); - expect(count).toBeGreaterThan(0); - done(); - }); - - it('shows the Lumi H5P Editor text', async (done) => { - const headline = await app.client.$('h1'); - const text = await headline.getText(); - - expect(text).toBe('Lumi H5P Editor'); - done(); - }); - - it('has the editor-startpage secondary button', async (done) => { - const button = await app.client.$('#editor-startpage-secondaryButton'); - - expect(button).toBeTruthy(); - done(); - }); -});