Skip to content

Commit d21a654

Browse files
committed
add error handling for note retrieval; update user role in setup; implement basic smoke tests and user detail retrieval tests
1 parent e473cbe commit d21a654

File tree

9 files changed

+1124
-0
lines changed

9 files changed

+1124
-0
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
'use strict'
2+
3+
const t = require('tap')
4+
const { createNote } = require('../../../../utils/note-creator')
5+
const { randomString } = require('../../../../utils/data-creator')
6+
const { randomUUID } = require('node:crypto')
7+
8+
t.test('GET by id /notes/:id 200 - Fetch note by id', async (t) => {
9+
// Arrange
10+
const { note, app, accessToken, refreshToken } = await createNote(t)
11+
12+
// Act
13+
const response = await app.inject({
14+
method: 'GET',
15+
url: `/notes/${note.id}`,
16+
headers: {
17+
'Content-Type': 'application/json',
18+
},
19+
cookies: {
20+
accessToken: accessToken,
21+
refreshToken: refreshToken,
22+
},
23+
})
24+
25+
// Assert
26+
t.equal(response.statusCode, 200)
27+
t.type(response.json(), 'object')
28+
t.equal(response.json().data.id, note.id)
29+
t.equal(response.json().data.title, note.title)
30+
t.equal(response.json().data.body, note.body)
31+
t.same(response.json().data.tags, note.tags)
32+
t.equal(response.json().data.createdAt, note.createdAt)
33+
t.equal(response.json().data.updatedAt, note.updatedAt)
34+
})
35+
36+
t.test('GET by id /notes/:id 404 - Note not found', async (t) => {
37+
// Arrange
38+
const { app, accessToken, refreshToken } = await createNote(t)
39+
const nonExistentNoteId = randomUUID()
40+
41+
// Act
42+
const response = await app.inject({
43+
method: 'GET',
44+
url: `/notes/${nonExistentNoteId}`,
45+
headers: {
46+
'Content-Type': 'application/json',
47+
},
48+
cookies: {
49+
accessToken: accessToken,
50+
refreshToken: refreshToken,
51+
},
52+
})
53+
54+
// Assert
55+
t.equal(response.statusCode, 404)
56+
t.type(response.json(), 'object')
57+
})
58+
59+
t.test('GET by id /notes/:id 400 - Invalid id format', async (t) => {
60+
// Arrange
61+
const { app, accessToken, refreshToken } = await createNote(t)
62+
const invalidNoteId = randomString('1234567890', 10)
63+
64+
// Act
65+
const response = await app.inject({
66+
method: 'GET',
67+
url: `/notes/${invalidNoteId}`,
68+
headers: {
69+
'Content-Type': 'application/json',
70+
},
71+
cookies: {
72+
accessToken: accessToken,
73+
refreshToken: refreshToken,
74+
},
75+
})
76+
77+
// Assert
78+
t.equal(response.statusCode, 400)
79+
t.type(response.json(), 'object')
80+
})
81+
82+
t.test('GET by id /notes/:id 401 - Unauthorized', async (t) => {
83+
// Arrange
84+
const { app } = await createNote(t)
85+
const nonExistentNoteId = randomUUID()
86+
const accessToken = 'invalid'
87+
const refreshToken = 'invalid'
88+
89+
// Act
90+
const response = await app.inject({
91+
method: 'GET',
92+
url: `/notes/${nonExistentNoteId}`,
93+
headers: {
94+
'Content-Type': 'application/json',
95+
},
96+
cookies: {
97+
accessToken: accessToken,
98+
refreshToken: refreshToken,
99+
},
100+
})
101+
102+
// Assert
103+
t.equal(response.statusCode, 401)
104+
t.type(response.json(), 'object')
105+
})
106+
107+
t.test('GET by id /notes/:id 404 - Note not found', async (t) => {
108+
// Arrange
109+
const { app, accessToken, refreshToken } = await createNote(t)
110+
const nonExistentNoteId = randomUUID()
111+
112+
// Act
113+
const response = await app.inject({
114+
method: 'GET',
115+
url: `/notes/${nonExistentNoteId}`,
116+
headers: {
117+
'Content-Type': 'application/json',
118+
},
119+
cookies: {
120+
accessToken: accessToken,
121+
refreshToken: refreshToken,
122+
},
123+
})
124+
125+
// Assert
126+
t.equal(response.statusCode, 404)
127+
t.type(response.json(), 'object')
128+
})
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
'use strict'
2+
3+
const t = require('tap')
4+
const { setup } = require('../../../../utils/setup-user')
5+
const { randomString } = require('../../../../utils/data-creator')
6+
7+
t.beforeEach(async (t) => {
8+
const { app, accessToken, refreshToken } = await setup(t)
9+
t.context.app = app
10+
t.context.accessToken = accessToken
11+
t.context.refreshToken = refreshToken
12+
13+
// Create a note before each test
14+
const noteTitle = randomString(10)
15+
const noteBody = randomString(20)
16+
const noteTags = [randomString(5)]
17+
18+
const response = await app.inject({
19+
method: 'POST',
20+
url: '/notes/',
21+
headers: {
22+
contentType: 'application/json',
23+
},
24+
cookies: {
25+
accessToken: accessToken,
26+
refreshToken: refreshToken,
27+
},
28+
payload: {
29+
title: noteTitle,
30+
body: noteBody,
31+
tags: noteTags,
32+
},
33+
})
34+
35+
t.equal(response.statusCode, 201)
36+
t.type(response.json(), 'object')
37+
t.ok(response.json().id)
38+
t.equal(typeof response.json().id, 'string')
39+
40+
t.context.noteId = response.json().id
41+
})
42+
43+
t.test('GET /notes 200 - List notes', async (t) => {
44+
// Arrange
45+
const { app, accessToken, refreshToken } = t.context
46+
47+
// Act
48+
const response = await app.inject({
49+
method: 'GET',
50+
url: '/notes',
51+
headers: {
52+
contentType: 'application/json',
53+
},
54+
cookies: {
55+
accessToken: accessToken,
56+
refreshToken: refreshToken,
57+
},
58+
})
59+
60+
// Assert
61+
t.equal(response.statusCode, 201)
62+
t.type(response.json(), 'object')
63+
t.ok(Array.isArray(response.json().data))
64+
t.type(response.json().totalCount, 'number')
65+
})
66+
67+
t.skip('GET /notes 200 - List notes with pagination', async (t) => {
68+
// Arrange
69+
const { app, accessToken, refreshToken } = t.context
70+
71+
// Act
72+
const response = await app.inject({
73+
method: 'GET',
74+
url: '/notes?skip=0&limit=2',
75+
headers: {
76+
contentType: 'application/json',
77+
},
78+
cookies: {
79+
accessToken: accessToken,
80+
refreshToken: refreshToken,
81+
},
82+
})
83+
84+
// Assert
85+
t.equal(response.statusCode, 201)
86+
t.type(response.json(), 'object')
87+
t.ok(Array.isArray(response.json().data))
88+
t.type(response.json().totalCount, 'number')
89+
t.equal(response.json().data.length, 2)
90+
})
91+
92+
t.test('GET /notes 200 - List notes with title filter', async (t) => {
93+
// Arrange
94+
const { app, accessToken, refreshToken } = t.context
95+
const title = 'testnote'
96+
97+
// Act
98+
const response = await app.inject({
99+
method: 'GET',
100+
url: `/notes?title=${title}`,
101+
headers: {
102+
contentType: 'application/json',
103+
},
104+
cookies: {
105+
accessToken: accessToken,
106+
refreshToken: refreshToken,
107+
},
108+
})
109+
110+
// Assert
111+
t.equal(response.statusCode, 201)
112+
t.type(response.json(), 'object')
113+
t.ok(Array.isArray(response.json().data))
114+
t.type(response.json().totalCount, 'number')
115+
t.ok(response.json().data.every((note) => note.title.includes(title)))
116+
})
117+
118+
t.test('GET /notes 400 - Invalid skip and limit', async (t) => {
119+
// Arrange
120+
const { app, accessToken, refreshToken } = t.context
121+
122+
// Act
123+
const response = await app.inject({
124+
method: 'GET',
125+
url: '/notes?skip=-1&limit=-5',
126+
headers: {
127+
contentType: 'application/json',
128+
},
129+
cookies: {
130+
accessToken: accessToken,
131+
refreshToken: refreshToken,
132+
},
133+
})
134+
135+
// Assert
136+
t.equal(response.statusCode, 400)
137+
t.type(response.json(), 'object')
138+
t.equal(response.json().message, 'Skip and limit must be non-negative integers')
139+
})
140+
141+
t.test('GET /notes 401 - Unauthorized', async (t) => {
142+
// Arrange
143+
const { app } = t.context
144+
145+
// Act
146+
const response = await app.inject({
147+
method: 'GET',
148+
url: '/notes',
149+
headers: {
150+
contentType: 'application/json',
151+
},
152+
})
153+
154+
// Assert
155+
t.equal(response.statusCode, 401)
156+
t.type(response.json(), 'object')
157+
})

0 commit comments

Comments
 (0)