Skip to content
This repository was archived by the owner on Nov 28, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/api-explorer/__tests__/Doc.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,15 @@ describe('Response Schema', () => {
});
});

describe('RenderLogs', () => {
test('should return a log component', () => {
const doc = mount(<Doc {...props} />);
doc.setProps({ Logs: {} });
const res = doc.instance().renderLogs();
expect(res).toBeTruthy();
});
});

describe('themes', () => {
test('should output code samples and responses in the right column', () => {
const doc = mount(<Doc {...props} appearance={{ referenceLayout: 'column' }} />);
Expand Down
16 changes: 15 additions & 1 deletion packages/api-explorer/src/Doc.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ class Doc extends React.Component {
url,
method,
}}
result={this.state.result}
group={this.props.group}
groups={this.props.groups}
changeGroup={this.props.changeGroup}
/>
);
}
Expand Down Expand Up @@ -398,6 +402,14 @@ Doc.propTypes = {
tryItMetrics: PropTypes.func.isRequired,
onAuthChange: PropTypes.func.isRequired,
lazy: PropTypes.bool.isRequired,
group: PropTypes.string,
groups: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
name: PropTypes.string,
}),
),
changeGroup: PropTypes.func.isRequired,
};

Doc.defaultProps = {
Expand All @@ -411,6 +423,8 @@ Doc.defaultProps = {
splitReferenceDocs: false,
},
Logs: undefined,
user: undefined,
user: {},
baseUrl: '/',
group: '',
groups: [],
};
26 changes: 26 additions & 0 deletions packages/api-explorer/src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,14 @@ class ApiExplorer extends React.Component {
changeSelected: this.changeSelected,
},
auth: getAuth(this.props.variables.user, this.props.oasFiles),
group: this.getGroup(),
};

this.changeGroup = this.changeGroup.bind(this);
this.groups =
this.props.variables.user.keys &&
this.props.variables.user.keys.map(key => ({ id: key.id, name: key.name }));

this.lazyHash = this.buildLazyHash();
}

Expand All @@ -42,6 +48,18 @@ class ApiExplorer extends React.Component {
});
}

getGroup() {
if (this.props.variables.user.keys && this.props.variables.user.keys[0].id) {
return this.props.variables.user.keys[0].id;
}

if (this.props.variables.user.id) {
return this.props.variables.user.id;
}

return undefined;
}

setLanguage(language) {
this.setState({ language });
Cookie.set('readme_language', language);
Expand Down Expand Up @@ -70,6 +88,10 @@ class ApiExplorer extends React.Component {
return this.props.oasFiles[apiSetting];
}

changeGroup(group) {
this.setState({ group });
}

isLazy(index) {
if (this.props.dontLazyLoad) return false;
return this.lazyHash[index];
Expand Down Expand Up @@ -147,6 +169,9 @@ class ApiExplorer extends React.Component {
setLanguage={this.setLanguage}
flags={this.props.flags}
user={this.props.variables.user}
group={this.state.group}
groups={this.groups}
changeGroup={this.changeGroup}
Logs={this.props.Logs}
baseUrl={this.props.baseUrl.replace(/\/$/, '')}
appearance={this.props.appearance}
Expand Down Expand Up @@ -188,6 +213,7 @@ ApiExplorer.propTypes = {
variables: PropTypes.shape({
user: PropTypes.shape({
keys: PropTypes.array,
id: PropTypes.string,
}).isRequired,
defaults: PropTypes.arrayOf(
PropTypes.shape({ name: PropTypes.string.isRequired, default: PropTypes.string.isRequired }),
Expand Down
193 changes: 121 additions & 72 deletions packages/api-logs/__tests__/index.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const React = require('react');
const { shallow } = require('enzyme');
const nock = require('nock');

const { Logs, LogsEmitter } = require('../index.jsx');
const { Logs, checkFreshness, handleResponse } = require('../index.jsx');
const requestmodel = require('./fixtures/requestmodel.json');
const oas = require('./fixtures/oas.json');
const operation = require('./fixtures/operation.json');
Expand All @@ -26,17 +26,24 @@ describe('Logs', () => {
url: `${oas.servers[0].url}${operation.path}`,
method: operation.method,
},
user: {
name: 'Gilfoyle',
email: 'gilfoyle@piedpiper.com',
isAdmin: true,
id: 'someid',
},
baseUrl,
group: 'someid',
groups: [
{
id: '1',
name: 'someid',
},
{
id: '2',
name: 'anotherId',
},
],
changeGroup: jest.fn(),
result: {},
};

test('should not render if user_data does not have id or keys.id', () => {
const noUser = { baseUrl, query: {} };
test('should not render if groups are not populated', () => {
const noUser = { baseUrl, query: {}, changeGroup: () => {} };
const comp = shallow(<LogTest {...noUser} />);

expect(comp.html()).toBe(null);
Expand All @@ -63,21 +70,73 @@ describe('Logs', () => {
expect(comp.find('.loading-container').length).toBe(1);
});

test('should call refresh and set state when group props are updated via parent', done => {
const comp = shallow(<LogTest {...props} />);
comp.instance().getLogs = jest.fn();
comp.setProps({ group: 'testnew' });
expect(comp.instance().getLogs).toHaveBeenCalledTimes(1);
expect(comp.instance().state.logs).toMatchObject([]);
done();
});

test('should make multiple requests for logs if conditional check fails', async () => {
const comp = shallow(<Logs {...props} />);
comp.setState({
logs: [requestmodel],
});

const mock = nock('https://docs.readme.com:443', { encodedQueryParams: true })
.get('/api/logs')
.query({
url: 'https%3A%2F%2Fdash.readme.io%2Fapi%2Fv1%2Fdocs%2F%7Bslug%7D',
id: 'someid',
method: 'delete',
limit: 5,
page: 0,
})
.reply(200, [requestmodel])
.get('/api/logs')
.query({
url: 'https%3A%2F%2Fdash.readme.io%2Fapi%2Fv1%2Fdocs%2F%7Bslug%7D',
id: 'someid',
method: 'delete',
limit: 5,
page: 0,
})
.reply(200, [
{
...requestmodel,
_id: '2',
},
]);

await comp.instance().iterativeGetLogs();
expect(comp.instance().state.logs[0]._id).toBe('2');
mock.done();
});

test('should call refresh when result props are updated via parent', () => {
const comp = shallow(<LogTest {...props} />);
comp.instance().iterativeGetLogs = jest.fn();
comp.setProps({ result: { newResult: true } });
expect(comp.instance().iterativeGetLogs).toHaveBeenCalledTimes(1);
});

test('should fetch based on query with page/limit', async () => {
const comp = shallow(<Logs {...props} />);

const mock = nock('https://docs.readme.com:443', { encodedQueryParams: true })
.get('/api/logs')
.query({
url: 'https%3A%2F%2Fdash.readme.io%2Fapi%2Fv1%2Fdocs%2F%7Bslug%7D',
id: null,
id: 'someid',
method: 'delete',
limit: 5,
page: 0,
})
.reply(200, [requestmodel]);

await comp.instance().getData();
await comp.instance().getLogs();

mock.done();
});
Expand All @@ -96,7 +155,7 @@ describe('Logs', () => {
})
.reply(200, [requestmodel]);

await comp.instance().getData('someid');
await comp.instance().getLogs('someid');

mock.done();
});
Expand All @@ -112,50 +171,10 @@ describe('Logs', () => {
const comp = shallow(<LogTest {...props} />);
comp.setState({ logs: [requestmodel] });

expect(comp.instance().state.group).toBe('someid');
expect(comp.find('table').length).toBe(1);
});

test('should render with key', () => {
const userData = {
name: 'Gilfoyle',
email: 'gilfoyle@piedpiper.com',
isAdmin: true,
keys: [{ id: 'one', name: 'one' }, { id: 'two', name: 'two' }],
};
props.user = userData;

const comp = shallow(<LogTest {...props} />);
comp.setState({ logs: [requestmodel] });

expect(comp.instance().state.group).toBe('one');
expect(comp.instance().state.groups.length).toBe(2);
expect(comp.instance().props.group).toBe('someid');
expect(comp.find('table').length).toBe(1);
});

test('should throw for invalid fetch', () => {
const comp = shallow(<Logs {...props} />);
expect(comp.instance().getData).toThrow();
});

test('should throw when response is 500', () => {
const comp = shallow(<Logs {...props} />);
const response = {
status: 500,
};
expect(comp.instance().handleData.bind(comp.instance(), response)).toThrow();
});

test('should set logs when response is 200', () => {
const comp = shallow(<Logs {...props} />);
const response = {
status: 200,
json: () => [requestmodel],
};
const result = comp.instance().handleData(response);
expect(result.length).toBe(1);
});

test('on select change', () => {
const comp = shallow(<Logs {...props} />);
const instance = comp.instance();
Expand All @@ -164,7 +183,7 @@ describe('Logs', () => {
value: '1230',
},
});
expect(instance.state.group).toBe('1230');
expect(instance.props.changeGroup).toHaveBeenCalledWith('1230');
});

test('open window on log visit', () => {
Expand All @@ -175,23 +194,6 @@ describe('Logs', () => {
expect(global.open).toBeCalled();
});

test('on stale call refresh', () => {
const comp = shallow(<Logs {...props} />);
comp.setState({ stale: true });
const instance = comp.instance();
jest.spyOn(instance, 'refresh');
instance.onVisible();
expect(instance.refresh).toHaveBeenCalledWith('1230');
});

test('remove listener on component unmount', () => {
const comp = shallow(<Logs {...props} />);
comp.setState({ stale: true });
const instance = comp.instance();
instance.componentWillUnmount();
expect(LogsEmitter.listeners().length).toBe(0);
});

test('when parsed agent is not Other', () => {
const comp = shallow(<LogTest {...props} />);
requestmodel.request.log.entries[0].request.headers[0].value = 'IE4.0';
Expand All @@ -214,8 +216,55 @@ describe('Logs', () => {
})
.reply(200, [requestmodel]);

await comp.instance().getData('someid');
await comp.instance().getLogs('someid');

mock.done();
});
});

describe('handleResponse()', () => {
test('should throw when response is 500', () => {
expect(() => {
handleResponse({ status: 500 });
}).toThrow();
});

test('should set logs when response is 200', () => {
const response = {
status: 200,
json: () => [requestmodel],
};
const result = handleResponse(response);
expect(result.length).toBe(1);
});
});

describe('checkFreshness()', () => {
test('should throw error if existing and new logs are unpopulated after request', () => {
expect(() => {
checkFreshness([], []);
}).toThrow();
});

test('should throw error if new logs are unpopulated after request', () => {
expect(() => {
checkFreshness([{ _id: 1 }], []);
}).toThrow();
});

test('should throw error if logs are not unique', () => {
expect(() => {
checkFreshness([{ _id: 1 }], [{ _id: 1 }]);
}).toThrow();
});

test('should return incoming logs if no existing logs, and incoming logs are populated', () => {
const res = checkFreshness([], [{ _id: 1 }]);
expect(res[0]._id).toBe(1);
});

test('should return incoming logs if both args are populated and ids are unique to each other', () => {
const res = checkFreshness([{ _id: 1 }], [{ _id: 2 }]);
expect(res[0]._id).toBe(2);
});
});
Loading