Skip to content
Open
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
150 changes: 110 additions & 40 deletions src/__tests__/auth.exercise.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,118 @@

// 🐨 import the things you'll need
// 💰 here, I'll just give them to you. You're welcome
// import axios from 'axios'
// import {resetDb} from 'utils/db-utils'
// import * as generate from 'utils/generate'
// import startServer from '../start'
import axios from 'axios'
import { resetDb } from 'utils/db-utils'
import * as generate from 'utils/generate'
import { handleRequestFailure, getData, resolve } from 'utils/async'
import * as usersDB from '../db/users'
import startServer from '../start'

// 🐨 you'll need to start/stop the server using beforeAll and afterAll
// 💰 This might be helpful: server = await startServer({port: 8000})
let api, server

// 🐨 beforeEach test in this file we want to reset the database
beforeAll(async () => {
server = await startServer({ port: 8000 })
const baseURL = `http://localhost:${server.address().port}/api`
api = axios.create({ baseURL })
api.interceptors.response.use(getData, handleRequestFailure)
})

afterAll(() => server.close())
beforeEach(() => resetDb())

test('auth flow', async () => {
// 🐨 get a username and password from generate.loginForm()
//
// register
// 🐨 use axios.post to post the username and password to the registration endpoint
// 💰 http://localhost:8000/api/auth/register
//
// 🐨 assert that the result you get back is correct
// 💰 it'll have an id and a token that will be random every time.
// You can either only check that `result.data.user.username` is correct, or
// for a little extra credit 💯 you can try using `expect.any(String)`
// (an asymmetric matcher) with toEqual.
// 📜 https://jestjs.io/docs/en/expect#expectanyconstructor
// 📜 https://jestjs.io/docs/en/expect#toequalvalue
//
// login
// 🐨 use axios.post to post the username and password again, but to the login endpoint
// 💰 http://localhost:8000/api/auth/login
//
// 🐨 assert that the result you get back is correct
// 💰 tip: the data you get back is exactly the same as the data you get back
// from the registration call, so this can be done really easily by comparing
// the data of those results with toEqual
//
// authenticated request
// 🐨 use axios.get(url, config) to GET the user's information
// 💰 http://localhost:8000/api/auth/me
// 💰 This request must be authenticated via the Authorization header which
// you can add to the config object: {headers: {Authorization: `Bearer ${token}`}}
// Remember that you have the token from the registration and login requests.
//
// 🐨 assert that the result you get back is correct
// 💰 (again, this should be the same data you get back in the other requests,
// so you can compare it with that).
const { username, password } = generate.loginForm()
const registerResponse = await api.post('auth/register', {
username,
password,
})

expect(registerResponse.user).toEqual({
token: expect.any(String),
id: expect.any(String),
username,
})

const loginResponse = await api.post('auth/login', {
username,
password,
})

expect(registerResponse.user).toEqual(loginResponse.user)

const meResponse = await api.get('auth/me', {
headers: {
Authorization: `Bearer ${loginResponse.user.token}`,
},
})

expect(loginResponse.user).toEqual(meResponse.user)
})

test('username must be unique', async () => {
const { username, password } = generate.loginForm()
await usersDB.insert(generate.buildUser({ username }))

const error = await api
.post('auth/register', {
username,
password,
})
.catch(resolve)

expect(error).toMatchInlineSnapshot(
`[Error: 400: {"message":"username taken"}]`,
)
})

test('get me unauthenticated returns error', async () => {
const error = await api.get('auth/me').catch(resolve)
expect(error).toMatchInlineSnapshot(
`[Error: 401: {"code":"credentials_required","message":"No authorization token was found"}]`,
)
})

test('username required to register', async () => {
const error = await api
.post('auth/register', { password: generate.password })
.catch(resolve)
expect(error).toMatchInlineSnapshot(
`[Error: 400: {"message":"username can't be blank"}]`,
)
})

test('password required to register', async () => {
const error = await api
.post('auth/register', { username: generate.username })
.catch(resolve)
expect(error).toMatchInlineSnapshot(
`[Error: 400: {"message":"username can't be blank"}]`,
)
})

test('username required to login', async () => {
const error = await api
.post('auth/login', { password: generate.password })
.catch(resolve)
expect(error).toMatchInlineSnapshot(
`[Error: 400: {"message":"username can't be blank"}]`,
)
})

test('password required to login', async () => {
const error = await api
.post('auth/login', { username: generate.username })
.catch(resolve)
expect(error).toMatchInlineSnapshot(
`[Error: 400: {"message":"username can't be blank"}]`,
)
})

test('user must exist to login', async () => {
const error = await api
.post('auth/login', generate.loginForm({ username: 'this_papu_not_exist' }))
.catch(resolve)
expect(error).toMatchInlineSnapshot(
`[Error: 400: {"message":"username or password is invalid"}]`,
)
})
57 changes: 28 additions & 29 deletions src/__tests__/list-items.exercise.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Testing CRUD API Routes

import axios from 'axios'
import {resetDb, insertTestUser} from 'utils/db-utils'
import {getData, handleRequestFailure, resolve} from 'utils/async'
import { resetDb, insertTestUser } from 'utils/db-utils'
import { getData, handleRequestFailure, resolve } from 'utils/async'
import * as generate from 'utils/generate'
import * as booksDB from '../db/books'
import startServer from '../start'
Expand All @@ -23,48 +23,47 @@ async function setup() {
// so I'm going to give it to you, but don't just skip over it. Try to figure
// out what's going on here.
const testUser = await insertTestUser()
const authAPI = axios.create({baseURL})
const authAPI = axios.create({ baseURL })
authAPI.defaults.headers.common.authorization = `Bearer ${testUser.token}`
authAPI.interceptors.response.use(getData, handleRequestFailure)
return {testUser, authAPI}
return { testUser, authAPI }
}

test('listItem CRUD', async () => {
const {testUser, authAPI} = await setup()
const { testUser, authAPI } = await setup()

// 🐨 create a book object and insert it into the database
// 💰 use generate.buildBook and await booksDB.insert
const book = generate.buildBook()
await booksDB.insert(book)

// CREATE
// 🐨 create a new list-item by posting to the list-items endpoint with a bookId
// 💰 the data you send should be: {bookId: book.id}

// 🐨 assert that the data you get back is correct
// 💰 it should have an ownerId (testUser.id) and a bookId (book.id)
// 💰 if you don't want to assert on all the other properties, you can use
// toMatchObject: https://jestjs.io/docs/en/expect#tomatchobjectobject

// 💰 you might find this useful for the future requests:
// const listItemId = cData.listItem.id
// const listItemIdUrl = `list-items/${listItemId}`
const cData = await authAPI.post('list-items', { bookId: book.id })
expect(cData.listItem).toMatchObject({
ownerId: testUser.id,
bookId: book.id,
})
const listItemId = cData.listItem.id
const listItemIdUrl = `list-items/${listItemId}`

// READ
// 🐨 make a GET to the `listItemIdUrl`
// 🐨 assert that this returns the same thing you got when you created the list item
const rData = await authAPI.get(listItemIdUrl)
expect(rData.listItem).toEqual(cData.listItem)

// UPDATE
// 🐨 make a PUT request to the `listItemIdUrl` with some updates
// 💰 const updates = {notes: generate.notes()}
// 🐨 assert that this returns the right stuff (should be the same as the READ except with the updated notes)
const updates = { notes: generate.notes() }
const uData = await authAPI.put(listItemIdUrl, updates)
expect(uData.listItem).toEqual({ ...rData.listItem, ...updates })

// DELETE
// 🐨 make a DELETE request to the `listItemIdUrl`
// 🐨 assert that this returns the right stuff (💰 {success: true})
const dData = await authAPI.delete(listItemIdUrl)
expect(dData).toEqual({ success: true })

const error = await authAPI.get(listItemIdUrl).catch(resolve)
expect(error.status).toBe(404)

// 🐨 try to make a GET request to the `listItemIdUrl` again.
// 💰 this promise should reject. You can do a try/catch if you want, or you
// can use the `resolve` utility from utils/async:
// 💰 const error = await authAPI.get(listItemIdUrl).catch(resolve)
const idlessMessage = error.data.message.replace(listItemId, 'LIST_ITEM_ID')
expect(idlessMessage).toMatchInlineSnapshot(
`"No list item was found with the id of LIST_ITEM_ID"`,
)
// 🐨 assert that the status is 404 and the error.data is correct
})

Expand Down
Loading