-
Notifications
You must be signed in to change notification settings - Fork 30
Test Suite written in Jest #33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
3444ae3
added jest
2e3c261
setup jest with babel for es6 imports
ee57fd1
verbs and interceptor tests
f7e0e1e
fetch Request tests
8ff487e
first half of fetchresponse
7a0e764
fetch_response tests v1
acf97c6
restructured tests
30607a2
cleaned test suite up
7fe94bc
removed comment and typo
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"env": { | ||
"test": { | ||
"plugins": ["@babel/plugin-transform-modules-commonjs"] | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
node_modules/ | ||
dist/ | ||
dist/ | ||
coverage/ | ||
|
||
.vscode |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
/** | ||
* @jest-environment jsdom | ||
*/ | ||
import 'isomorphic-fetch' | ||
import { FetchRequest } from '../src/fetch_request' | ||
import { FetchResponse } from '../src/fetch_response' | ||
|
||
jest.mock('../src/lib/utils', () => { | ||
const originalModule = jest.requireActual('../src/lib/utils') | ||
return { | ||
__esModule: true, | ||
...originalModule, | ||
getCookie: jest.fn().mockReturnValue('mock-csrf-token'), | ||
metaContent: jest.fn() | ||
} | ||
}) | ||
|
||
describe('perform', () => { | ||
test('request is performed with 200', async () => { | ||
const mockResponse = new Response("success!", { status: 200 }) | ||
window.fetch = jest.fn().mockResolvedValue(mockResponse) | ||
|
||
const testRequest = new FetchRequest("get", "localhost") | ||
const testResponse = await testRequest.perform() | ||
|
||
expect(window.fetch).toHaveBeenCalledTimes(1) | ||
expect(window.fetch).toHaveBeenCalledWith("localhost", testRequest.fetchOptions) | ||
expect(testResponse).toStrictEqual(new FetchResponse(mockResponse)) | ||
}) | ||
|
||
test('request is performed with 401', async () => { | ||
const mockResponse = new Response(undefined, { status: 401, headers: {'WWW-Authenticate': 'https://localhost/login'}}) | ||
window.fetch = jest.fn().mockResolvedValue(mockResponse) | ||
|
||
delete window.location | ||
window.location = new URL('https://www.example.com') | ||
expect(window.location.href).toBe('https://www.example.com/') | ||
|
||
const testRequest = new FetchRequest("get", "https://localhost") | ||
expect(testRequest.perform()).rejects.toBe('https://localhost/login') | ||
|
||
testRequest.perform().catch(() => { | ||
expect(window.location.href).toBe('https://localhost/login') | ||
}) | ||
}) | ||
|
||
test('turbo stream request automatically calls renderTurboStream', async () => { | ||
const mockResponse = new Response('', { status: 200, headers: { 'Content-Type': 'text/vnd.turbo-stream.html' }}) | ||
window.fetch = jest.fn().mockResolvedValue(mockResponse) | ||
jest.spyOn(FetchResponse.prototype, "ok", "get").mockReturnValue(true) | ||
jest.spyOn(FetchResponse.prototype, "isTurboStream", "get").mockReturnValue(true) | ||
const renderSpy = jest.spyOn(FetchResponse.prototype, "renderTurboStream").mockImplementation() | ||
|
||
const testRequest = new FetchRequest("get", "localhost") | ||
await testRequest.perform() | ||
|
||
expect(renderSpy).toHaveBeenCalledTimes(1) | ||
}) | ||
}) | ||
|
||
test('treat method name case-insensitive', async () => { | ||
const methodNames = [ "gEt", "GeT", "get", "GET"] | ||
for (const methodName of methodNames) { | ||
const testRequest = new FetchRequest(methodName, "localhost") | ||
expect(testRequest.fetchOptions.method).toBe("GET") | ||
} | ||
}) | ||
|
||
describe('header handling', () => { | ||
const defaultHeaders = { | ||
'X-Requested-With': 'XMLHttpRequest', | ||
'X-CSRF-Token': 'mock-csrf-token', | ||
'Accept': 'text/html, application/xhtml+xml' | ||
} | ||
describe('responseKind', () => { | ||
test('none', async () => { | ||
const defaultRequest = new FetchRequest("get", "localhost") | ||
expect(defaultRequest.fetchOptions.headers) | ||
.toStrictEqual(defaultHeaders) | ||
}) | ||
test('html', async () => { | ||
const htmlRequest = new FetchRequest("get", "localhost", { responseKind: 'html' }) | ||
expect(htmlRequest.fetchOptions.headers) | ||
.toStrictEqual(defaultHeaders) | ||
}) | ||
test('json', async () => { | ||
const jsonRequest = new FetchRequest("get", "localhost", { responseKind: 'json' }) | ||
expect(jsonRequest.fetchOptions.headers) | ||
.toStrictEqual({...defaultHeaders, 'Accept' : 'application/json'}) | ||
}) | ||
test('turbo-stream', async () => { | ||
const turboRequest = new FetchRequest("get", "localhost", { responseKind: 'turbo-stream' }) | ||
expect(turboRequest.fetchOptions.headers) | ||
.toStrictEqual({...defaultHeaders, 'Accept' : 'text/vnd.turbo-stream.html, text/html, application/xhtml+xml'}) | ||
}) | ||
test('invalid', async () => { | ||
const invalidResponseKindRequest = new FetchRequest("get", "localhost", { responseKind: 'exotic' }) | ||
expect(invalidResponseKindRequest.fetchOptions.headers) | ||
.toStrictEqual({...defaultHeaders, 'Accept' : '*/*'}) | ||
}) | ||
}) | ||
|
||
describe('contentType', () => { | ||
test('is added to headers', () => { | ||
const customRequest = new FetchRequest("get", "localhost/test.json", { contentType: 'any/thing' }) | ||
expect(customRequest.fetchOptions.headers) | ||
.toStrictEqual({ ...defaultHeaders, "Content-Type": 'any/thing'}) | ||
}) | ||
test('is not set by formData', () => { | ||
const formData = new FormData() | ||
formData.append("this", "value") | ||
const formDataRequest = new FetchRequest("get", "localhost", { body: formData }) | ||
expect(formDataRequest.fetchOptions.headers) | ||
.toStrictEqual(defaultHeaders) | ||
}) | ||
test('is set by file body', () => { | ||
const file = new File(["contenxt"], "file.txt", { type: "text/plain" }) | ||
const fileRequest = new FetchRequest("get", "localhost", { body: file }) | ||
expect(fileRequest.fetchOptions.headers) | ||
.toStrictEqual({ ...defaultHeaders, "Content-Type": "text/plain"}) | ||
}) | ||
test('is set by json body', () => { | ||
const jsonRequest = new FetchRequest("get", "localhost", { body: { some: "json"} }) | ||
expect(jsonRequest.fetchOptions.headers) | ||
.toStrictEqual({ ...defaultHeaders, "Content-Type": "application/json"}) | ||
}) | ||
}) | ||
|
||
test('additional headers are appended', () => { | ||
const request = new FetchRequest("get", "localhost", { contentType: "application/json", headers: { custom: "Header" } }) | ||
expect(request.fetchOptions.headers) | ||
.toStrictEqual({ ...defaultHeaders, custom: "Header", "Content-Type": "application/json"}) | ||
request.addHeader("test", "header") | ||
expect(request.fetchOptions.headers) | ||
.toStrictEqual({ ...defaultHeaders, custom: "Header", "Content-Type": "application/json", "test": "header"}) | ||
}) | ||
|
||
test('headers win over contentType', () => { | ||
const request = new FetchRequest("get", "localhost", { contentType: "application/json", headers: { "Content-Type": "this/overwrites" } }) | ||
expect(request.fetchOptions.headers) | ||
.toStrictEqual({ ...defaultHeaders, "Content-Type": "this/overwrites"}) | ||
}) | ||
|
||
test('serializes JSON to String', () => { | ||
const jsonBody = { some: "json" } | ||
let request | ||
request = new FetchRequest("get", "localhost", { body: jsonBody, contentType: "application/json" }) | ||
expect(request.fetchOptions.body).toBe(JSON.stringify(jsonBody)) | ||
|
||
request = new FetchRequest("get", "localhost", { body: jsonBody }) | ||
expect(request.fetchOptions.body).toBe(JSON.stringify(jsonBody)) | ||
}) | ||
|
||
test('not serializes JSON with explicit different contentType', () => { | ||
const jsonBody = { some: "json" } | ||
const request = new FetchRequest("get", "localhost", { body: jsonBody, contentType: "not/json" }) | ||
expect(request.fetchOptions.body).toBe(jsonBody) | ||
}) | ||
|
||
test('set redirect', () => { | ||
let request | ||
const redirectTypes = [ "follow", "error", "manual" ] | ||
for (const redirect of redirectTypes) { | ||
request = new FetchRequest("get", "localhost", { redirect }) | ||
expect(request.fetchOptions.redirect).toBe(redirect) | ||
} | ||
|
||
request = new FetchRequest("get", "localhost") | ||
expect(request.fetchOptions.redirect).toBe("follow") | ||
|
||
// maybe check for valid values and default to follow? | ||
// https://developer.mozilla.org/en-US/docs/Web/API/Request/redirect | ||
request = new FetchRequest("get", "localhost", { redirect: "nonsense"}) | ||
expect(request.fetchOptions.redirect).toBe("nonsense") | ||
}) | ||
|
||
test('sets signal', () => { | ||
let request | ||
request = new FetchRequest("get", "localhost") | ||
expect(request.fetchOptions.signal).toBe(undefined) | ||
|
||
request = new FetchRequest("get", "localhost", { signal: "signal"}) | ||
expect(request.fetchOptions.signal).toBe("signal") | ||
}) | ||
|
||
test('has fixed credentials setting which cannot be changed', () => { | ||
let request | ||
request = new FetchRequest("get", "localhost") | ||
expect(request.fetchOptions.credentials).toBe('same-origin') | ||
|
||
// has no effect | ||
request = new FetchRequest("get", "localhost", { credentials: "omit"}) | ||
expect(request.fetchOptions.credentials).toBe('same-origin') | ||
}) | ||
}) | ||
|
||
describe('query params are parsed', () => { | ||
test('anchors are rejected', () => { | ||
const testRequest = new FetchRequest("post", "localhost/test?a=1&b=2#anchor", { query: { c: 3 } }) | ||
expect(testRequest.url).toBe("localhost/test?a=1&b=2&c=3") | ||
// const brokenRequest = new FetchRequest("post", "localhost/test#anchor", { query: { a: 1, b: 2, c: 3 } }) | ||
// expect(brokenRequest.url).toBe("localhost/test?a=1&b=2&c=3") | ||
marcelolx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}) | ||
test('url and options are merged', () => { | ||
const urlAndOptionRequest = new FetchRequest("post", "localhost/test?a=1&b=2", { query: { c: 3 } }) | ||
expect(urlAndOptionRequest.url).toBe("localhost/test?a=1&b=2&c=3") | ||
}) | ||
test('only url', () => { | ||
const urlRequest = new FetchRequest("post", "localhost/test?a=1&b=2") | ||
expect(urlRequest.url).toBe("localhost/test?a=1&b=2") | ||
}) | ||
test('only options', () => { | ||
const optionRequest = new FetchRequest("post", "localhost/test", { query: { c: 3 } }) | ||
expect(optionRequest.url).toBe("localhost/test?c=3") | ||
}) | ||
test('options accept formData', () => { | ||
const formData = new FormData() | ||
formData.append("a", 1) | ||
|
||
const urlAndOptionRequest = new FetchRequest("post", "localhost/test", { query: formData }) | ||
expect(urlAndOptionRequest.url).toBe("localhost/test?a=1") | ||
}) | ||
test('options accept urlSearchParams', () => { | ||
const urlSearchParams = new URLSearchParams() | ||
urlSearchParams.append("a", 1) | ||
|
||
const urlAndOptionRequest = new FetchRequest("post", "localhost/test", { query: urlSearchParams }) | ||
expect(urlAndOptionRequest.url).toBe("localhost/test?a=1") | ||
}) | ||
test('handles empty query', () => { | ||
const emptyQueryRequest = new FetchRequest("get", "localhost/test") | ||
expect(emptyQueryRequest.url).toBe("localhost/test") | ||
}) | ||
}) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the default being checked in the prior check? About checking valid values, I don't think that's necessary, since Fetch API will raise an error if the user provides an invalid value. At least I think that we would be testing Fetch API behavior and not Request.JS behavior. Having a test that proves that it's possible to override the default value provided by request.js is enough, like the test bellow (even if that isn't a valid value)