Skip to content

Commit

Permalink
fix(gui): reconnect to database on tests end event (#411)
Browse files Browse the repository at this point in the history
* fix(gui): reconnect to database on tests end event

* fix(details component): call handler with current state

* feat: add ability to share html-reporter action names with its plugins
  • Loading branch information
DudaGod authored Nov 18, 2021
1 parent 99e2c8b commit 002b43d
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 50 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ directory.
The routes then can be called from the plugin React components defined in the `plugin.js`. For convenience the plugin name is always passed with options when function- or array-returning form is used to export plugin as the function options property `pluginName`:

```js
export default ['react', 'axios', function(React, axios, {pluginName, pluginConfig, actions, selectors}) {
export default ['react', 'axios', function(React, axios, {pluginName, pluginConfig, actions, actionNames, selectors}) {
class PluginComponent extends React.Component {
// ... somewhere inside the component ...
const result = await axios.get(`/plugin-routes/${pluginName}/plugin-route`);
Expand All @@ -271,9 +271,11 @@ directory.

In the example you can also see another convenient properties:
- `pluginName` - plugin name;
- `pluginConfig` - plugin configuration;
- `actions` - the html-reporter **Redux** actions;
- `selectors` - the memoized html-reporter selectors which created using **reselect** library
- `pluginConfig` - plugin configuration.
- `actionNames` - the html-reporter action names, that used in **Redux** actions. To be able to subscribe on html-reporter events;
- `selectors` - the memoized html-reporter selectors which created using **reselect** library.


Available dependencies:
- `react`
Expand Down
12 changes: 8 additions & 4 deletions lib/static/components/details.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ export default class Details extends Component {
state = {isOpened: false};

handleClick = () => {
this.setState({isOpened: !this.state.isOpened});
this.setState((state, props) => {
const newState = {isOpened: !state.isOpened};

if (this.props.onClick) {
this.props.onClick();
}
if (props.onClick) {
props.onClick(newState);
}

return newState;
});
}

render() {
Expand Down
2 changes: 1 addition & 1 deletion lib/static/modules/action-names.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default {
SUITE_BEGIN: 'SUITE_BEGIN',
TEST_BEGIN: 'TEST_BEGIN',
TEST_RESULT: 'TEST_RESULT',
TESTS_END: 'TEST_END',
TESTS_END: 'TESTS_END',
ACCEPT_SCREENSHOT: 'ACCEPT_SCREENSHOT',
ACCEPT_OPENED_SCREENSHOTS: 'ACCEPT_OPENED_SCREENSHOTS',
CLOSE_SECTIONS: 'CLOSE_SECTIONS',
Expand Down
20 changes: 16 additions & 4 deletions lib/static/modules/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import StaticTestsTreeBuilder from '../../tests-tree-builder/static';
import actionNames from './action-names';
import {types as modalTypes} from '../components/modals';
import {QUEUED} from '../../constants/test-statuses';
import {LOCAL_DATABASE_NAME} from '../../constants/file-names';
import {getHttpErrorMessage} from './utils';
import {fetchDatabases, mergeDatabases, connectToDatabase} from './sqlite';
import {fetchDatabases, mergeDatabases, connectToDatabase, getMainDatabaseUrl} from './sqlite';
import {getSuitesTableRows} from './database-utils';
import {setFilteredBrowsers} from './query-params';
import plugins from './plugins';
Expand All @@ -23,7 +22,7 @@ export const initGuiReport = () => {
try {
const appState = await axios.get('/init');

const mainDatabaseUrl = new URL(LOCAL_DATABASE_NAME, window.location.href);
const mainDatabaseUrl = getMainDatabaseUrl();
const db = await connectToDatabase(mainDatabaseUrl.href);

await plugins.loadAll(appState.data.config);
Expand Down Expand Up @@ -148,6 +147,20 @@ export const stopTests = () => async dispatch => {
}
};

export const testsEnd = () => async dispatch => {
try {
const mainDatabaseUrl = getMainDatabaseUrl();
const db = await connectToDatabase(mainDatabaseUrl.href);

dispatch({
type: actionNames.TESTS_END,
payload: {db}
});
} catch (e) {
dispatch(createNotificationError('testsEnd', e));
}
};

export const suiteBegin = (suite) => ({type: actionNames.SUITE_BEGIN, payload: suite});
export const testBegin = (test) => ({type: actionNames.TEST_BEGIN, payload: test});
export const testResult = (result) => ({type: actionNames.TEST_RESULT, payload: result});
Expand All @@ -157,7 +170,6 @@ export const toggleLoading = (payload) => ({type: actionNames.TOGGLE_LOADING, pa
export const closeSections = (payload) => ({type: actionNames.CLOSE_SECTIONS, payload});
export const openModal = (payload) => ({type: actionNames.OPEN_MODAL, payload});
export const closeModal = (payload) => ({type: actionNames.CLOSE_MODAL, payload});
export const testsEnd = () => ({type: actionNames.TESTS_END});
export const runFailed = () => ({type: actionNames.RUN_FAILED_TESTS});
export const expandAll = () => ({type: actionNames.VIEW_EXPAND_ALL});
export const expandErrors = () => ({type: actionNames.VIEW_EXPAND_ERRORS});
Expand Down
3 changes: 2 additions & 1 deletion lib/static/modules/load-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import immer from 'immer';
import * as reselect from 'reselect';
import axios from 'axios';
import * as selectors from './selectors';
import actionNames from './action-names';
import Details from '../components/details';

const whitelistedDeps = {
Expand Down Expand Up @@ -85,7 +86,7 @@ async function initPlugin(plugin, pluginName, pluginConfig) {
const depArgs = deps.map(dep => whitelistedDeps[dep]);
// cyclic dep, resolve it dynamically
const actions = await import('./actions');
return plugin(...depArgs, {pluginName, pluginConfig, actions, selectors});
return plugin(...depArgs, {pluginName, pluginConfig, actions, actionNames, selectors});
}

return plugin;
Expand Down
8 changes: 8 additions & 0 deletions lib/static/modules/reducers/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ export default (state, action) => {
case actionNames.INIT_STATIC_REPORT:
case actionNames.INIT_GUI_REPORT: {
const {db} = action.payload;

return {...state, db};
}

case actionNames.TESTS_END: {
closeDatabase(state.db); // close previous connection in order to free memory
const {db} = action.payload;

return {...state, db};
}

Expand Down
8 changes: 7 additions & 1 deletion lib/static/modules/sqlite.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import axios from 'axios';
import {flattenDeep} from 'lodash';
import {mergeTables} from '../../common-utils';
import {LOCAL_DATABASE_NAME} from '../../constants/file-names';

function isRelativeUrl(url) {
try {
Expand Down Expand Up @@ -139,8 +140,13 @@ async function connectToDatabase(dbUrl) {
return new SQL.Database(new Uint8Array(data));
}

function getMainDatabaseUrl() {
return new URL(LOCAL_DATABASE_NAME, window.location.href);
}

module.exports = {
fetchDatabases,
mergeDatabases,
connectToDatabase
connectToDatabase,
getMainDatabaseUrl
};
36 changes: 27 additions & 9 deletions test/unit/lib/static/components/details.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,34 @@ describe('<Details />', () => {
assert.equal(text, 'some-title');
});

it('should call "onClick" handler on click in title', () => {
const props = {
title: 'some-title',
content: 'foo bar',
onClick: sinon.stub()
};
describe('"onClick" handler', () => {
let props;

const component = mount(<Details {...props} />);
component.find('.details__summary').simulate('click');
beforeEach(() => {
props = {
title: 'some-title',
content: 'foo bar',
onClick: sinon.stub()
};
});

it('should call on click in title', () => {
const component = mount(<Details {...props} />);

component.find('.details__summary').simulate('click');

assert.calledOnce(props.onClick);
});

it('should call with changed state on each call', () => {
const component = mount(<Details {...props} />);

component.find('.details__summary')
.simulate('click')
.simulate('click');

assert.calledOnceWith(props.onClick);
assert.calledWith(props.onClick.firstCall, {isOpened: true});
assert.calledWith(props.onClick.secondCall, {isOpened: false});
});
});
});
57 changes: 44 additions & 13 deletions test/unit/lib/static/modules/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import {LOCAL_DATABASE_NAME} from 'lib/constants/file-names';

describe('lib/static/modules/actions', () => {
const sandbox = sinon.sandbox.create();
let dispatch, actions, addNotification, getSuitesTableRows, connectToDatabaseStub, pluginsStub;
let dispatch, actions, addNotification, getSuitesTableRows, getMainDatabaseUrl, connectToDatabaseStub, pluginsStub;

beforeEach(() => {
dispatch = sandbox.stub();
sandbox.stub(axios, 'post').resolves({data: {}});
addNotification = sandbox.stub();
getSuitesTableRows = sandbox.stub();
getMainDatabaseUrl = sandbox.stub().returns({href: 'http://localhost/default/sqlite.db'});
connectToDatabaseStub = sandbox.stub().resolves({});
pluginsStub = {loadAll: sandbox.stub()};

Expand All @@ -23,7 +24,7 @@ describe('lib/static/modules/actions', () => {
actions = proxyquire('lib/static/modules/actions', {
'reapop': {addNotification},
'./database-utils': {getSuitesTableRows},
'./sqlite': {connectToDatabase: connectToDatabaseStub},
'./sqlite': {getMainDatabaseUrl, connectToDatabase: connectToDatabaseStub},
'./plugins': pluginsStub
});
});
Expand All @@ -33,16 +34,6 @@ describe('lib/static/modules/actions', () => {
describe('initGuiReport', () => {
beforeEach(() => {
sandbox.stub(axios, 'get').resolves({data: {}});

global.window = {
location: {
href: 'http://localhost/random/path.html'
}
};
});

afterEach(() => {
global.window = undefined;
});

it('should run init action on server', async () => {
Expand All @@ -52,7 +43,8 @@ describe('lib/static/modules/actions', () => {
});

it('should fetch database from default html page', async () => {
global.window.location.href = 'http://127.0.0.1:8080/';
const href = 'http://127.0.0.1:8080/sqlite.db';
getMainDatabaseUrl.returns({href});

await actions.initGuiReport()(dispatch);

Expand Down Expand Up @@ -330,4 +322,43 @@ describe('lib/static/modules/actions', () => {
assert.deepEqual(actions.closeModal(modal), {type: actionNames.CLOSE_MODAL, payload: modal});
});
});

describe('testsEnd', () => {
it('should connect to database', async () => {
const href = 'http://127.0.0.1:8080/sqlite.db';
getMainDatabaseUrl.returns({href});

await actions.testsEnd()(dispatch);

assert.calledOnceWith(connectToDatabaseStub, href);
});

it('should dispatch "TESTS_END" action with db connection', async () => {
const db = {};
connectToDatabaseStub.resolves(db);

await actions.testsEnd()(dispatch);

assert.calledOnceWith(dispatch, {
type: actionNames.TESTS_END,
payload: {db}
});
});

it('should show notification if error appears', async () => {
connectToDatabaseStub.rejects(new Error('failed to connect to database'));

await actions.testsEnd()(dispatch);

assert.calledOnceWith(
addNotification,
{
dismissAfter: 0,
id: 'testsEnd',
message: 'failed to connect to database',
status: 'error'
}
);
});
});
});
9 changes: 5 additions & 4 deletions test/unit/lib/static/modules/load-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import axios from 'axios';
import loadPlugin from 'lib/static/modules/load-plugin';
import actionNames from 'lib/static/modules/action-names';
import * as actions from 'lib/static/modules/actions';
import * as selectors from 'lib/static/modules/selectors';

Expand Down Expand Up @@ -32,7 +33,7 @@ describe('static/modules/load-plugin', () => {
await loadPlugin('plugin-a');

assert.deepStrictEqual(plugin.args, [
[{actions, selectors, pluginName: 'plugin-a', pluginConfig: undefined}]
[{actions, actionNames, selectors, pluginName: 'plugin-a', pluginConfig: undefined}]
]);
});

Expand All @@ -41,7 +42,7 @@ describe('static/modules/load-plugin', () => {
await loadPlugin('plugin-b', config);

assert.deepStrictEqual(plugin.args, [
[{actions, selectors, pluginName: 'plugin-b', pluginConfig: config}]
[{actions, actionNames, selectors, pluginName: 'plugin-b', pluginConfig: config}]
]);
});

Expand All @@ -50,7 +51,7 @@ describe('static/modules/load-plugin', () => {
await loadPlugin('plugin-c');

assert.deepStrictEqual(plugin.args, [
[axios, {actions, selectors, pluginName: 'plugin-c', pluginConfig: undefined}]
[axios, {actions, actionNames, selectors, pluginName: 'plugin-c', pluginConfig: undefined}]
]);
});

Expand All @@ -59,7 +60,7 @@ describe('static/modules/load-plugin', () => {
await loadPlugin('plugin-d');

assert.deepStrictEqual(plugin.args, [
[undefined, {actions, selectors, pluginName: 'plugin-d', pluginConfig: undefined}]
[undefined, {actions, actionNames, selectors, pluginName: 'plugin-d', pluginConfig: undefined}]
]);
});
});
Expand Down
Loading

0 comments on commit 002b43d

Please sign in to comment.