it('should log out user', () => { const userId = 'USER_ID'; fetchMock.mock( '/gdc/account/token', 'GET', 200 ); fetchMock.mock( '/gdc/app/account/bootstrap', 'GET', { status: 200, body: JSON.stringify({ bootstrapResource: { accountSetting: { links: { self: `/gdc/account/profile/${userId}` } } } }) } ); fetchMock.mock( `/gdc/account/login/${userId}`, 'DELETE', 200 // should be 204, but see https://github.com/wheresrhys/fetch-mock/issues/36 ); return user.logout().then(r => expect(r.ok).to.be.ok()); });
it("rejects when response is an array (error)", () => { fetchMock.mock(SERVICES.CSRF_TOKEN, "token"); fetchMock.mock(SERVICES.LOGIN, ["foo"]); let loginPromise = codRemoteService.login("foo", "bar"); return expect(loginPromise).to.eventually.be.rejected; });
it("rejects when response is not [true]", () => { fetchMock.mock(SERVICES.CSRF_TOKEN, "token"); fetchMock.mock(SERVICES.LOGOUT, ["foo"]); let logoutPromise = codRemoteService.logout(); return expect(logoutPromise).to.eventually.be.rejected; });
it("doesn't reject when cookie expired", () => { fetchMock.mock(SERVICES.CSRF_TOKEN, "token"); fetchMock.mock(SERVICES.LOGOUT, ["User is not logged in."]); let logoutPromise = codRemoteService.logout(); return expect(logoutPromise).eventually.not.to.be.rejected; });
it("fails when server responds with an error", () => { fetchMock.mock(SERVICES.EVALUATIONS, "GET", [{nid: "300"}]); fetchMock.mock(SERVICES.EVALUATIONS, "POST", ["error"]); fetchMock.mock(SERVICES.CSRF_TOKEN, "token"); let evaluation = codRemoteService.createEvaluation("200", "foo"); return expect(evaluation).to.eventually.be.rejectedWith("error"); });
it("fails when server sends an unexpected response", () => { fetchMock.mock(SERVICES.EVALUATIONS, "GET", [{nid: "300"}]); fetchMock.mock(SERVICES.EVALUATIONS, "POST", {foo: "bar"}); fetchMock.mock(SERVICES.CSRF_TOKEN, "token"); let evaluation = codRemoteService.createEvaluation("200", "foo"); return expect(evaluation).to.eventually.be.rejectedWith("Could not submit evaluation."); });
const mockAll = ({ groupsResponse, linksResponse, rollupsResponse, resultsResponses, alignmentsResponse }) => { fetchMock.mock('/api/v1/courses/1/outcome_groups?per_page=100', groupsResponse) fetchMock.mock('/api/v1/courses/1/outcome_group_links?outcome_style=full&per_page=100', linksResponse) fetchMock.mock('/api/v1/courses/1/outcome_rollups?user_ids[]=2&per_page=100', rollupsResponse) fetchMock.mock('/api/v1/courses/1/outcome_alignments?student_id=2', alignmentsResponse) Object.keys(resultsResponses).forEach((id) => { fetchMock.mock( `/api/v1/courses/1/outcome_results?user_ids[]=2&outcome_ids[]=${id}&include[]=assignments&per_page=100`, resultsResponses[id] ) }) }
describe('parseJson', () => { fetchMock.mock('http://google.com/foo', '{"foo": "bar"}'); fetchMock.mock('http://google.com/empty', 204); fetchMock.mock('http://google.com/created', 201); fetchMock.mock('http://google.com/error', new Promise(resolve => { resolve({ status: 422, body: { foo: 'bar', } }); })); fetchMock.mock('http://google.com/html-error', new Promise(resolve => { resolve({ status: 422, body: '<p>Error!</p>' }); })); it('can parse a JSON response', () => { return fetch('http://google.com/foo').then(parseJson).then(response => { expect(response.data).toEqual({foo: 'bar'}); }); }); it('does not crash on 204 responses', () => { return fetch('http://google.com/empty').then(parseJson).then(response => { expect(response.data).toBeFalsy(); }); }); it('ignores empty responses', () => { return fetch('http://google.com/created').then(parseJson).then(response => { expect(response.data).toBeFalsy(); }); }); it('can parse contents of error responses', () => { return fetch('http://google.com/error').then(parseJson).catch(response => { expect(response.message).toEqual('Unprocessable Entity'); expect(response.data).toEqual({foo: 'bar'}); }); }); it('can parse html error respnses', () => { return fetch('http://google.com/html-error').then(parseJson).catch(response => { expect(response.message).toEqual('Unprocessable Entity'); expect(response.data).toEqual('<p>Error!</p>'); }) }); });
it("should 'just work' by using provided credentials from the config.", (done) => { let mockOptions = mockData.tokenIssue(); fetchMock.mock(mockData.root()); fetchMock.mock(mockOptions); const keystone = new Keystone(mockData.config); keystone .tokenIssue() .then((token) => { expect(token).toEqual('test_token'); // From mock data done(); }) .catch((error) => done.fail(error)); });
it("creates an evaluation", () => { let evaluationResponse = {nid: "200"}; fetchMock.mock(SERVICES.EVALUATIONS, "GET", [{nid: "300"}]); fetchMock.mock(SERVICES.EVALUATIONS, "POST", evaluationResponse); fetchMock.mock(SERVICES.CSRF_TOKEN, "token"); return codRemoteService.createEvaluation("200", "foo", "+1").then(response => { expect(response).to.deep.equal(evaluationResponse); let body = JSON.parse(fetchMock.lastCall()[1].body); expect(body.session_id).to.equal("200"); expect(body.comment).to.equal("foo"); expect(body.rating).to.equal("+1"); }); });
it("sends logout request", () => { fetchMock.mock(SERVICES.CSRF_TOKEN, "token"); fetchMock.mock(SERVICES.LOGOUT, [true]); return codRemoteService.logout() .then(response => { expect(fetchMock.called(SERVICES.CSRF_TOKEN)).to.be.true; expect(fetchMock.called(SERVICES.LOGOUT)).to.be.true; expect(fetchMock.lastCall()[1].method).to.equal("post"); expect(fetchMock.lastCall()[1].headers).to.deep.equal({ Accept: "application/json", "Content-Type": "application/json", "X-CSRF-Token": "token" }); expect(response).to.deep.equal([true]); }); });
it('fires ADD and FAILED on failed post create request', () => { fetchMock.mock(`${host}/api/posts/`, 500); const post = { _id: 999, created: '2016-01-01', location: { x: 1, y: 2 }, image: { mimetype: 'image/jpeg', path: '/test/', name: 'image-name.jpg' }, public: false, text: 'Test post 1' }; const expectedActions = [{ type: actions.ADD_POST }, { type: actions.ADD_POST_FAILED, error: 'Internal Server Error' }]; const store = mockStore({ posts: [] }); return store.dispatch(actions.createPost(post)) .then(() => { expect(store.getActions()).to.deep.equal(expectedActions); }); });
it("should be used to create the meta of the error completion action", () => { fetchMock.mock("http://testserver/someurl/", "POST", {throws: new Error("argh")}) actionCreator(dispatch) return expect(dispatchedPromiseTwo).to.eventually.have.deep.property( "meta.test", "result" ) })
it('should use markdown from HTML on fetch error', () => { fetchMock .mock(gistUrl + '123/raw', 404); const store = mockStore({ notebook: Immutable.fromJS({ metadata: { datasources: {} }, blocks: 'stubBlocks', content: 'stubContent' }), execution: Immutable.fromJS({ data: {} }) }); const expected = [ {type: actions.LOAD_MARKDOWN, markdown: testMd}, {type: actions.EXECUTE_AUTO, content: 'stubContent', blocks: 'stubBlocks'} ]; return store.dispatch(actions.loadMarkdown()) .then(() => { expect(store.getActions()).to.eql(expected); }); });
it("sends login request to service", () => { fetchMock.mock(SERVICES.CSRF_TOKEN, "token"); fetchMock.mock(SERVICES.LOGIN, {}); return codRemoteService.login("foo", "bar") .then(response => { expect(fetchMock.called(SERVICES.CSRF_TOKEN)).to.be.true; expect(fetchMock.called(SERVICES.LOGIN)).to.be.true; expect(fetchMock.lastCall()[1].method).to.equal("post"); expect(fetchMock.lastCall()[1].headers).to.deep.equal({ Accept: "application/json", "Content-Type": "application/json", "X-CSRF-Token": "token" }); expect(fetchMock.lastCall()[1].body).to.deep.equal(JSON.stringify({username: "******", password: "******"})); expect(response).to.deep.equal({}); }); });
it('should create LOAD_MARKDOWN with received markdown', () => { const md = '## Some markdown'; fetchMock .mock(gistUrl + '123/raw', {body: md}); const store = mockStore({ notebook: Immutable.fromJS({ metadata: { datasources: {} }, blocks: 'stubBlocks', content: 'stubContent' }), execution: Immutable.fromJS({ data: {} }) }); const expected = [ {type: actions.LOAD_MARKDOWN, markdown: md}, {type: actions.EXECUTE_AUTO, content: 'stubContent', blocks: 'stubBlocks'} ]; return store.dispatch(actions.loadMarkdown()) .then(() => { expect(store.getActions()).to.eql(expected); }); });
it('should not fetch data unless necessary', () => { fetchMock .mock('http://example.com/data1', {body: {thing: 'data1'}}) .mock('http://example.com/data2', {body: {thing: 'data2'}}); const store = mockStore({ notebook: Immutable.fromJS({ metadata: { datasources: { one: 'http://example.com/data1', two: 'http://example.com/data2' } }, blocks: 'stubBlocks', content: 'stubContent' }), execution: Immutable.fromJS({ data: {one: 'hooray'} }) }); const expected = [ {type: actions.RECEIVED_DATA, name: 'two', data: {thing: 'data2'}}, {type: actions.EXECUTE_AUTO, blocks: 'stubBlocks', content: 'stubContent'} ]; return store.dispatch(actions.fetchData()) .then(() => { expect(store.getActions()).to.eql(expected); }); });
beforeEach(() => { store = mockStore(); fetchMock.mock(GET_LOG_URL, { status: 200, body: { _id: 1 }, }); });
specify('succesful', (done) => { const response = { status: 500 } const matcher = function(url, opts) { expect(opts.headers['Content-Type']).toBe('application/json') const body = JSON.parse(opts.body) expect(body.app).toExist() expect(body.publicKey).toExist() expect(body.nonce).toExist() expect(body.permissions).toExist() const applicationAssymetricKeys = { publicKey: new Uint8Array(new Buffer(body.publicKey, 'base64')), nonce: new Uint8Array(new Buffer(body.nonce, 'base64')) } const launcherAssymetricKeys = libsodium.crypto_box_keypair() const launcherSymmetricKey = libsodium.randombytes_buf(libsodium.crypto_secretbox_KEYBYTES) const launcherSymmetricNonce = libsodium.randombytes_buf(libsodium.crypto_secretbox_NONCEBYTES) const content = new Uint8Array(launcherSymmetricKey.byteLength + launcherSymmetricNonce.byteLength) content.set(new Uint8Array(launcherSymmetricKey), 0) content.set(new Uint8Array(launcherSymmetricNonce), launcherSymmetricKey.byteLength) const data = libsodium.crypto_box_easy( content, applicationAssymetricKeys.nonce, applicationAssymetricKeys.publicKey, launcherAssymetricKeys.privateKey ) response.status = 200 response.body = JSON.stringify({ token: 'token', permissions: [], publicKey: new Buffer(launcherAssymetricKeys.publicKey).toString('base64'), encryptedKey: new Buffer(data).toString('base64'), __launcherSymmetricKey: new Buffer(launcherSymmetricKey).toString('base64'), __launcherSymmetricNonce: new Buffer(launcherSymmetricNonce).toString('base64') }) return url === 'http://localhost:8100/auth' } fetch.mock(matcher, 'POST', response) http.postAuth((assymetricKeys, assymetricNonce) => { return function(response) { expect(response.status).toEqual(200) expect(response.__parsedResponseBody__.token).toBe('token') expect(response.__parsedResponseBody__.permissions).toEqual([]) expect(response.__parsedResponseBody__.publicKey).toExist() expect(response.__parsedResponseBody__.encryptedKey).toExist() http.fulfillPostAuth(assymetricKeys, assymetricNonce)(response) expect(response.__parsedResponseBody__.symmetricKeys.key).toBe(response.__parsedResponseBody__.__launcherSymmetricKey) expect(response.__parsedResponseBody__.symmetricKeys.nonce).toBe(response.__parsedResponseBody__.__launcherSymmetricNonce) done() } }) })
beforeEach(() => { store = mockStore(); fetchMock.mock(UPDATE_LOG_URL, { method: 'POST', status: 500, }); });
it("doesn't call service more than once if fetch is already taking place", () => { fetchMock.mock(SCHEDULED_SESSIONS_SERVICE, {}); Promise.all([fetcher.fetch(), fetcher.fetch()]).then(() => { expect(fetchMock.calls().length).to.equal(1); }); });
it('fires ADD and COMPLETE on successful post creation', () => { const post = { _id: 999, created: '2016-01-01', location: { x: 1, y: 2 }, image: { mimetype: 'image/jpeg', path: '/test/', name: 'image-name.jpg' }, public: false, text: 'Test post 1' }; fetchMock.mock(`${host}/api/posts/`, post); const expectedActions = [{ type: actions.ADD_POST }, { type: actions.ADD_POST_COMPLETE, post }]; const store = mockStore({ posts: [] }); return store.dispatch(actions.createPost(post)) .then(() => { expect(store.getActions()).to.deep.equal(expectedActions); }); });
it('invokes onAuthenticate callback on successful registration', (done) => { fetchMock.mock('/api/accounts/register', { status: 200, body: { token: 'JWT ATOKENGOESHERE', name: 'aname', email: '*****@*****.**', password: '******' } }); const onAuth = sinon.spy(); const wrapper = shallow( <Register logoText="logo" onAuthenticate={onAuth} apiEndpoint="/api/accounts/register" /> ); wrapper.instance().setState({ name: 'aname', email: '*****@*****.**', password: '******' }); wrapper.instance().handleSubmit().should.be.fulfilled().then(() => { expect(wrapper.state('error')).to.equal(null); expect(wrapper.state('loading')).to.be.false(); expect(onAuth.calledOnce).to.be.true(); }).should.notify(done); });
beforeEach(() => { store = mockStore(); fetchMock.mock(GET_ITEMS_URL, { status: 200, body: [{ a: 1 }], }); });
it('fires REQUEST and COMPLETE on successful posts request', () => { const posts = [{ created: '2016-01-01', location: { x: 1, y: 2 }, image: { mimetype: 'image/jpeg', path: '/test/', name: 'image-name.jpg' }, public: false, text: 'Test post 1' }]; fetchMock.mock(`${host}/api/posts/`, posts); const expectedActions = [{ type: actions.REQUEST_POSTS }, { type: actions.REQUEST_POSTS_COMPLETE, posts }]; const store = mockStore({ posts: [] }); return store.dispatch(actions.fetchPosts()) .then(() => { expect(store.getActions()).to.deep.equal(expectedActions); }); });
it("fails when response is an error", () => { fetchMock.mock(SERVICES.EVALUATIONS, ["User is not logged in."]); let evaluations = codRemoteService.evaluations(); return expect(evaluations).to.eventually.be.rejectedWith(/User is not logged in/); });
beforeEach(() => { store = mockStore(); fetchMock.mock(DELETE_LOGS_URL, { method: 'PATCH', status: 500, }); });
it("fails when evaluation is already submitted", () => { fetchMock.mock(SERVICES.EVALUATIONS, [{nid: "200"}]); let evaluation = codRemoteService.createEvaluation("200", "foo"); return expect(evaluation).to.eventually.be.rejectedWith(/already submitted/); });
beforeEach(() => { fetchMock .mock(`${BASE_URL}/foo`, { status: 200, body: {msg: 'world'} }) });
specify('succesful', (done) => { fetch.mock(matcher, 'DELETE', 200) http.deleteAuth('token').then((response) => { expect(response.status).toEqual(200) done() }) })