@thepalaceproject/circulation-admin 0.0.0-post.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +59 -0
- package/.node-version +1 -0
- package/.nvmrc +1 -0
- package/.prettierrc.json +10 -0
- package/.sass-lint.yml +37 -0
- package/CHANGELOG.md +946 -0
- package/README.md +155 -0
- package/dist/060b2710bdbbe3dfe48b58d59bd5f1fb.svg +288 -0
- package/dist/0db1520f47986b6c755a.svg +1 -0
- package/dist/1e59d2330b4c6deb84b3.ttf +0 -0
- package/dist/20fd1704ea223900efa9.woff2 +0 -0
- package/dist/4692b9ec53fd5972caa2.ttf +0 -0
- package/dist/5be1347c682810f199c7.eot +0 -0
- package/dist/6563aa3790be8329e4f2.svg +1 -0
- package/dist/82b1212e45a2bc35dd73.woff +0 -0
- package/dist/8b43027f47b20503057d.eot +0 -0
- package/dist/PalaceCollectionManagerLogo.svg +122 -0
- package/dist/be810be3a3e14c682a25.woff2 +0 -0
- package/dist/c1e38fd9e0e74ba58f7a2b77ef29fdd3.svg +2671 -0
- package/dist/circulation-admin.css +6841 -0
- package/dist/circulation-admin.js +2 -0
- package/dist/circulation-admin.js.LICENSE.txt +153 -0
- package/dist/f691f37e57f04c152e23.woff +0 -0
- package/jest.config.js +15 -0
- package/jest.polyfills.js +12 -0
- package/nightwatch.json +58 -0
- package/package.json +155 -0
- package/pull_request_template.md +22 -0
- package/requirements-ci.txt +1 -0
- package/testReporter.js +31 -0
- package/tests/__data__/statisticsApiResponseData.ts +327 -0
- package/tests/__mocks__/fileMock.js +1 -0
- package/tests/__mocks__/styleMock.js +1 -0
- package/tests/browser/README.md +19 -0
- package/tests/browser/assertions/noError.js +38 -0
- package/tests/browser/commands/goHome.js +13 -0
- package/tests/browser/commands/signIn.js +18 -0
- package/tests/browser/globals.js.sample +5 -0
- package/tests/browser/navigate.js +294 -0
- package/tests/browser/pages/book.js +21 -0
- package/tests/browser/pages/catalog.js +24 -0
- package/tests/browser/pages/login.js +11 -0
- package/tests/browser/redirect.js +104 -0
- package/tests/browser/signInFailure.js +22 -0
- package/tests/jest/README.md +6 -0
- package/tests/jest/api/admin.test.ts +60 -0
- package/tests/jest/businessRules/roleBasedAccess.test.ts +250 -0
- package/tests/jest/components/AdvancedSearchBuilder.test.tsx +38 -0
- package/tests/jest/components/BookEditor.test.tsx +240 -0
- package/tests/jest/components/CirculationEventsDownload.test.tsx +65 -0
- package/tests/jest/components/CustomLists.test.tsx +203 -0
- package/tests/jest/components/EditableInput.test.tsx +64 -0
- package/tests/jest/components/IndividualAdminEditForm.test.tsx +128 -0
- package/tests/jest/components/InventoryReportRequestModal.test.tsx +652 -0
- package/tests/jest/components/Lane.test.tsx +78 -0
- package/tests/jest/components/LaneEditor.test.tsx +148 -0
- package/tests/jest/components/ProtocolFormField.test.tsx +37 -0
- package/tests/jest/components/QuicksightDashboard.test.tsx +67 -0
- package/tests/jest/components/Stats.test.tsx +699 -0
- package/tests/jest/context/AppContext.test.tsx +113 -0
- package/tests/jest/features/book.test.ts +396 -0
- package/tests/jest/jest-setup.ts +1 -0
- package/tests/jest/sample/sample.test.js +3 -0
- package/tests/jest/testUtils/renderWithContext.tsx +38 -0
- package/tests/jest/testUtils/withProviders.tsx +92 -0
- package/tests/jest/utils/NoCacheDataFetcher.test.ts +75 -0
- package/tsconfig.json +25 -0
- package/tslint.json +56 -0
- package/webpack.common.js +72 -0
- package/webpack.dev-server.config.js +215 -0
- package/webpack.dev.config.js +9 -0
- package/webpack.prod.config.js +8 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
const breadcrumbSelector = "ol.breadcrumb";
|
|
2
|
+
let loadingSelector;
|
|
3
|
+
let catalogPage;
|
|
4
|
+
let bookPage;
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
/**
|
|
8
|
+
* Before any tests run, log in with the correct credentials.
|
|
9
|
+
*/
|
|
10
|
+
before: (browser, done) => {
|
|
11
|
+
const { username, password } = browser.globals;
|
|
12
|
+
catalogPage = browser.page.catalog();
|
|
13
|
+
bookPage = browser.page.book();
|
|
14
|
+
loadingSelector = catalogPage.elements.loadingSelector;
|
|
15
|
+
|
|
16
|
+
browser
|
|
17
|
+
.resizeWindow(1200, 900)
|
|
18
|
+
.signIn(username, password)
|
|
19
|
+
.perform(() => {
|
|
20
|
+
done();
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
"navigate to the first lane and back": function(browser) {
|
|
25
|
+
const { laneSelector } = catalogPage.elements;
|
|
26
|
+
const { nthBreadcrumbSelector } = catalogPage;
|
|
27
|
+
|
|
28
|
+
browser
|
|
29
|
+
.goHome()
|
|
30
|
+
.url(function(result) {
|
|
31
|
+
let catalogUrl = result.value;
|
|
32
|
+
this.getAttribute(laneSelector, "href", function(result) {
|
|
33
|
+
let laneUrl = result.value;
|
|
34
|
+
this.getText(laneSelector, function(laneText) {
|
|
35
|
+
let laneTitle = laneText.value;
|
|
36
|
+
|
|
37
|
+
this.click(laneSelector)
|
|
38
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
39
|
+
.verify.noError()
|
|
40
|
+
.verify.urlEquals(laneUrl)
|
|
41
|
+
.verify.titleContains(laneTitle)
|
|
42
|
+
// when a lane selector is clicked, we go into another
|
|
43
|
+
// navigation level
|
|
44
|
+
.verify.elementPresent(nthBreadcrumbSelector(3))
|
|
45
|
+
.back()
|
|
46
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
47
|
+
.verify.urlEquals(catalogUrl)
|
|
48
|
+
.verify.elementNotPresent(nthBreadcrumbSelector(3));
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
"navigate to the first book in the first lane and back": function(browser) {
|
|
55
|
+
const {
|
|
56
|
+
bookSelector,
|
|
57
|
+
bookLinkTitleSelector
|
|
58
|
+
} = catalogPage.elements;
|
|
59
|
+
const { bookTitleSelector } = bookPage.elements;
|
|
60
|
+
|
|
61
|
+
browser
|
|
62
|
+
.goHome()
|
|
63
|
+
.url(function(result) {
|
|
64
|
+
let catalogUrl = result.value;
|
|
65
|
+
this.getAttribute(bookSelector, "href", function(result) {
|
|
66
|
+
let bookUrl = result.value;
|
|
67
|
+
this.getText(bookLinkTitleSelector, function(result) {
|
|
68
|
+
let bookTitle = result.value;
|
|
69
|
+
this
|
|
70
|
+
.click(bookSelector)
|
|
71
|
+
.waitForElementPresent(bookTitleSelector, 5000)
|
|
72
|
+
.verify.noError()
|
|
73
|
+
.verify.urlEquals(bookUrl)
|
|
74
|
+
.verify.titleContains(bookTitle)
|
|
75
|
+
.verify.containsText(bookTitleSelector, bookTitle)
|
|
76
|
+
.back()
|
|
77
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
78
|
+
.verify.urlEquals(catalogUrl)
|
|
79
|
+
.verify.elementNotPresent(bookTitleSelector);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
"navigate to the first book, click through tabs, refresh page, go back": function(browser) {
|
|
86
|
+
const { bookSelector } = catalogPage.elements;
|
|
87
|
+
const {
|
|
88
|
+
bookTitleSelector,
|
|
89
|
+
titleInputSelector,
|
|
90
|
+
genreInputSelector,
|
|
91
|
+
coverInputSelector,
|
|
92
|
+
complaintInputSelector,
|
|
93
|
+
listInputSelector,
|
|
94
|
+
editTabSelector,
|
|
95
|
+
classificationsTabSelector,
|
|
96
|
+
coverTabSelector,
|
|
97
|
+
complaintsTabSelector,
|
|
98
|
+
listsTabSelector
|
|
99
|
+
} = bookPage.elements;
|
|
100
|
+
|
|
101
|
+
browser
|
|
102
|
+
.goHome()
|
|
103
|
+
.getAttribute(bookSelector, "href", function(result) {
|
|
104
|
+
let bookUrl = result.value;
|
|
105
|
+
this.getAttribute(bookSelector, "title", function(result) {
|
|
106
|
+
let bookTitle = result.value;
|
|
107
|
+
this
|
|
108
|
+
.click(bookSelector)
|
|
109
|
+
.waitForElementPresent(bookTitleSelector, 5000)
|
|
110
|
+
.verify.noError()
|
|
111
|
+
.verify.urlEquals(bookUrl)
|
|
112
|
+
.verify.containsText(bookTitleSelector, bookTitle)
|
|
113
|
+
|
|
114
|
+
// go to the edit tab
|
|
115
|
+
.click(editTabSelector)
|
|
116
|
+
.waitForElementPresent(titleInputSelector, 5000)
|
|
117
|
+
.verify.urlContains("tab/edit")
|
|
118
|
+
.verify.value(titleInputSelector, bookTitle)
|
|
119
|
+
|
|
120
|
+
// go to the classifications tab
|
|
121
|
+
.click(classificationsTabSelector)
|
|
122
|
+
.waitForElementPresent(genreInputSelector, 5000)
|
|
123
|
+
.verify.urlContains("tab/classifications")
|
|
124
|
+
|
|
125
|
+
// go to the image cover tab
|
|
126
|
+
.click(coverTabSelector)
|
|
127
|
+
.waitForElementPresent(coverInputSelector, 5000)
|
|
128
|
+
.verify.urlContains("tab/cover")
|
|
129
|
+
|
|
130
|
+
// go to the complaints tab
|
|
131
|
+
.click(complaintsTabSelector)
|
|
132
|
+
.waitForElementPresent(complaintInputSelector, 5000)
|
|
133
|
+
.verify.urlContains("tab/complaints")
|
|
134
|
+
.refresh()
|
|
135
|
+
.waitForElementPresent(complaintInputSelector, 5000)
|
|
136
|
+
.verify.urlContains("tab/complaints")
|
|
137
|
+
.verify.titleContains(bookTitle)
|
|
138
|
+
|
|
139
|
+
// go to the list tab
|
|
140
|
+
.click(listsTabSelector)
|
|
141
|
+
.waitForElementPresent(listInputSelector, 5000)
|
|
142
|
+
.verify.urlContains("tab/list")
|
|
143
|
+
|
|
144
|
+
// go back to the complaints tab
|
|
145
|
+
.back()
|
|
146
|
+
// go back to the cover tab
|
|
147
|
+
.back()
|
|
148
|
+
// go back to the classifications tab
|
|
149
|
+
.back()
|
|
150
|
+
// go back to the edit tab
|
|
151
|
+
.back()
|
|
152
|
+
// go back to the main details tab
|
|
153
|
+
.back()
|
|
154
|
+
.waitForElementPresent(bookTitleSelector, 5000)
|
|
155
|
+
.verify.urlEquals(bookUrl);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
"navigate to top-level feeds": function(browser) {
|
|
161
|
+
const {
|
|
162
|
+
laneSelector,
|
|
163
|
+
complaintsSelector,
|
|
164
|
+
hiddenSelector
|
|
165
|
+
} = catalogPage.elements;
|
|
166
|
+
const { nthBreadcrumbSelector } = catalogPage;
|
|
167
|
+
|
|
168
|
+
browser
|
|
169
|
+
.goHome()
|
|
170
|
+
.getAttribute(complaintsSelector, "href", function(result) {
|
|
171
|
+
let complaintsUrl = result.value;
|
|
172
|
+
this.getText(complaintsSelector, function(result) {
|
|
173
|
+
let complaintsTitle = result.value;
|
|
174
|
+
this.getAttribute(hiddenSelector, "href", function(result) {
|
|
175
|
+
let hiddenUrl = result.value
|
|
176
|
+
this.getText(hiddenSelector, function(result) {
|
|
177
|
+
let hiddenTitle = result.value;
|
|
178
|
+
this.getText(laneSelector, function(result) {
|
|
179
|
+
let laneTitle = result.value;
|
|
180
|
+
this
|
|
181
|
+
// go to the first lane
|
|
182
|
+
.click(laneSelector)
|
|
183
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
184
|
+
.waitForElementPresent(nthBreadcrumbSelector(2), 5000)
|
|
185
|
+
.assert.noError()
|
|
186
|
+
.verify.containsText(nthBreadcrumbSelector(1), "All Books")
|
|
187
|
+
.verify.containsText(nthBreadcrumbSelector(2), "Book")
|
|
188
|
+
.verify.containsText(nthBreadcrumbSelector(3), laneTitle)
|
|
189
|
+
|
|
190
|
+
// go to the complaints page
|
|
191
|
+
.click(complaintsSelector)
|
|
192
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
193
|
+
.assert.noError()
|
|
194
|
+
.assert.containsText(nthBreadcrumbSelector(1), "All Books")
|
|
195
|
+
.assert.containsText(nthBreadcrumbSelector(2), complaintsTitle)
|
|
196
|
+
.verify.urlEquals(complaintsUrl)
|
|
197
|
+
|
|
198
|
+
// go to the hidden books page
|
|
199
|
+
.click(hiddenSelector)
|
|
200
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
201
|
+
.assert.noError()
|
|
202
|
+
.assert.containsText(nthBreadcrumbSelector(1), "All Books")
|
|
203
|
+
.assert.containsText(nthBreadcrumbSelector(2), hiddenTitle)
|
|
204
|
+
.verify.urlEquals(hiddenUrl);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
"navigate to dashboard and back to catalog": function(browser) {
|
|
213
|
+
const {
|
|
214
|
+
catalogSelector,
|
|
215
|
+
dashboardSelector,
|
|
216
|
+
circulationLibraryStatsSelector,
|
|
217
|
+
circulationAllStatsSelector,
|
|
218
|
+
} = catalogPage.elements;
|
|
219
|
+
const { nthBreadcrumbSelector } = catalogPage;
|
|
220
|
+
|
|
221
|
+
browser
|
|
222
|
+
.goHome()
|
|
223
|
+
.getAttribute(nthBreadcrumbSelector(1), "title", function(result) {
|
|
224
|
+
let libraryName = result.value;
|
|
225
|
+
this.getAttribute(catalogSelector, "href", function(result) {
|
|
226
|
+
let catalogUrl = result.value;
|
|
227
|
+
this.getAttribute(dashboardSelector, "href", function(result) {
|
|
228
|
+
let dashboardUrl = result.value
|
|
229
|
+
this
|
|
230
|
+
// go to the dashboard
|
|
231
|
+
.click(dashboardSelector)
|
|
232
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
233
|
+
.assert.noError()
|
|
234
|
+
.verify.elementPresent(circulationLibraryStatsSelector)
|
|
235
|
+
.verify.elementPresent(circulationAllStatsSelector)
|
|
236
|
+
.verify.titleContains("Palace Collection Manager - Dashboard")
|
|
237
|
+
|
|
238
|
+
// click the main navigation link
|
|
239
|
+
.click(catalogSelector)
|
|
240
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
241
|
+
.assert.noError()
|
|
242
|
+
.verify.elementPresent(nthBreadcrumbSelector(1))
|
|
243
|
+
.verify.urlEquals(catalogUrl)
|
|
244
|
+
.verify.titleContains(`Palace Collection Manager - ${libraryName}`);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
"navigate to two different book detail pages": function(browser) {
|
|
251
|
+
const {
|
|
252
|
+
laneSelector,
|
|
253
|
+
firstBookSelector,
|
|
254
|
+
secondBookSelector
|
|
255
|
+
} = catalogPage.elements;
|
|
256
|
+
const { bookTitleSelector } = bookPage.elements;
|
|
257
|
+
const { nthBreadcrumbSelector } = catalogPage;
|
|
258
|
+
|
|
259
|
+
browser
|
|
260
|
+
.goHome()
|
|
261
|
+
|
|
262
|
+
// go to the first book
|
|
263
|
+
.click(firstBookSelector)
|
|
264
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
265
|
+
.waitForElementPresent(bookTitleSelector, 5000)
|
|
266
|
+
.getText(bookTitleSelector, function(result) {
|
|
267
|
+
let firstTitle = result.value;
|
|
268
|
+
|
|
269
|
+
this
|
|
270
|
+
// go back to the catalog
|
|
271
|
+
.click(nthBreadcrumbSelector(1))
|
|
272
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
273
|
+
.waitForElementPresent(secondBookSelector, 5000)
|
|
274
|
+
|
|
275
|
+
// go to the second book
|
|
276
|
+
.click(secondBookSelector)
|
|
277
|
+
.waitForElementNotPresent(loadingSelector, 5000)
|
|
278
|
+
.waitForElementPresent(bookTitleSelector, 50000)
|
|
279
|
+
|
|
280
|
+
// making sure that we are on a new book
|
|
281
|
+
.getText(bookTitleSelector, function(result) {
|
|
282
|
+
let secondTitle = result.value;
|
|
283
|
+
this.assert.notEqual(firstTitle, secondTitle);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Correctly end the selenium server and tests
|
|
290
|
+
*/
|
|
291
|
+
after: (browser) => {
|
|
292
|
+
browser.end();
|
|
293
|
+
}
|
|
294
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Page Object for a book page
|
|
2
|
+
module.exports = {
|
|
3
|
+
elements: {
|
|
4
|
+
// Elements found on each tab
|
|
5
|
+
bookTitleSelector: ".book-details .title",
|
|
6
|
+
titleInputSelector: "input[name='title']",
|
|
7
|
+
genreInputSelector: "select[name='genre']",
|
|
8
|
+
// 2nd child because the first is a label
|
|
9
|
+
genreSecondOptionSelector: "select[name='genre'] option:nth-child(2)",
|
|
10
|
+
coverInputSelector: "input[name='cover_url']",
|
|
11
|
+
complaintInputSelector: "select[name='type']",
|
|
12
|
+
listInputSelector: "input[name='list']",
|
|
13
|
+
// Tab selectors
|
|
14
|
+
detailsTabSelector: "ul.nav-tabs li:nth-child(1) a",
|
|
15
|
+
editTabSelector: "ul.nav-tabs li:nth-child(2) a",
|
|
16
|
+
classificationsTabSelector: "ul.nav-tabs li:nth-child(3) a",
|
|
17
|
+
coverTabSelector: "ul.nav-tabs li:nth-child(4) a",
|
|
18
|
+
complaintsTabSelector: "ul.nav-tabs li:nth-child(5) a",
|
|
19
|
+
listsTabSelector: "ul.nav-tabs li:nth-child(6) a",
|
|
20
|
+
}
|
|
21
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Page Object for the catalog
|
|
2
|
+
module.exports = {
|
|
3
|
+
elements: {
|
|
4
|
+
loadingSelector: ".loading",
|
|
5
|
+
laneSelector: "li:first-child .lane h2 a",
|
|
6
|
+
bookSelector: ".lane-books li:first-child a",
|
|
7
|
+
bookLinkTitleSelector: ".lane-books li:first-child a .title",
|
|
8
|
+
catalogSelector: "ul.nav li:nth-child(1) a",
|
|
9
|
+
complaintsSelector: "ul.nav li:nth-child(2) a",
|
|
10
|
+
hiddenSelector: "ul.nav li:nth-child(3) a",
|
|
11
|
+
dashboardSelector: "ul.nav li:nth-child(6) a",
|
|
12
|
+
circulationLibraryStatsSelector: ".library-stats:nth-child(1) h2",
|
|
13
|
+
circulationAllStatsSelector: ".library-stats:nth-child(2) h2",
|
|
14
|
+
firstBookSelector: "li:nth-child(1) .book a",
|
|
15
|
+
secondBookSelector: "li:nth-child(2) .book a",
|
|
16
|
+
},
|
|
17
|
+
commands: [
|
|
18
|
+
{
|
|
19
|
+
nthBreadcrumbSelector: function(n) {
|
|
20
|
+
return `ol.breadcrumb li:nth-child(${n})`
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const http = require('follow-redirects').http
|
|
2
|
+
|
|
3
|
+
const fetchGroupPage = (browser) => {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
http.get({
|
|
6
|
+
host: "localhost",
|
|
7
|
+
port: 6500,
|
|
8
|
+
path: "/groups/"
|
|
9
|
+
}, (response) => {
|
|
10
|
+
let body = "";
|
|
11
|
+
|
|
12
|
+
response.on("data", (chunk) => {
|
|
13
|
+
body += chunk;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
response.on("error", (err) => {
|
|
17
|
+
reject(err);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
response.on("end", () => {
|
|
21
|
+
resolve(body);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const getAdminBookUrlAndTitle = (body, browser) => {
|
|
27
|
+
const bookTitle = body.match(/<entry [\s\S]+?<title>([^<]+)<\/title>/i)[1];
|
|
28
|
+
const link = body.match(/<link [^>]*rel="alternate[^>]+\/>/i)[0];
|
|
29
|
+
const id = body.match(/<id>[\s\S]+?<\/id>/i)[0];
|
|
30
|
+
const lib = id.match(/\/[\w]+/i)[0]; // includes forward slash
|
|
31
|
+
const bookUrl = link.match(/href="([^"]+)"/)[1];
|
|
32
|
+
const entryBaseUrl = browser.globals.homeUrl.replace("/admin/web/", lib + "/works");
|
|
33
|
+
|
|
34
|
+
// transform the book url into an admin book url
|
|
35
|
+
const adminBookUrl =
|
|
36
|
+
browser.globals.homeUrl + "collection" + lib + "/book" + lib +
|
|
37
|
+
encodeURIComponent(
|
|
38
|
+
bookUrl.replace(entryBaseUrl, "")
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return { adminBookUrl, bookTitle };
|
|
42
|
+
};
|
|
43
|
+
const getAdminListUrl = (body, browser) => {
|
|
44
|
+
const listBaseUrl = `${browser.globals.homeUrl}lists`;
|
|
45
|
+
const id = body.match(/<id>[\s\S]+?<\/id>/i)[0];
|
|
46
|
+
const libraryName = id.match(/\/[\w]+/i)[0]; // includes forward slash
|
|
47
|
+
|
|
48
|
+
return `${listBaseUrl}${libraryName}`;
|
|
49
|
+
};
|
|
50
|
+
let body;
|
|
51
|
+
let loginPage;
|
|
52
|
+
let loadingSelector;
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
beforeEach: (browser, done) => {
|
|
56
|
+
loginPage = browser.page.login();
|
|
57
|
+
loadingSelector = browser.page.catalog().elements.loadingSelector;
|
|
58
|
+
|
|
59
|
+
fetchGroupPage(browser)
|
|
60
|
+
.then(data => {
|
|
61
|
+
body = data
|
|
62
|
+
done();
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
"attempt to view the admin list page before signing in": (browser) => {
|
|
67
|
+
const adminListUrl = getAdminListUrl(body, browser);
|
|
68
|
+
const { username, password, submit } = loginPage.elements;
|
|
69
|
+
|
|
70
|
+
// Go to the admin list page, get redirected to the login page with the
|
|
71
|
+
// redirect in the url, log in successfully, then go to the admin list page
|
|
72
|
+
browser
|
|
73
|
+
.url(adminListUrl)
|
|
74
|
+
.waitForElementVisible(username, 1000)
|
|
75
|
+
.assert.urlContains("redirect=" + encodeURIComponent(adminListUrl))
|
|
76
|
+
.setValue(username, browser.globals.username)
|
|
77
|
+
.setValue(password, browser.globals.password)
|
|
78
|
+
.click(submit)
|
|
79
|
+
.waitForElementVisible(loadingSelector, 1000)
|
|
80
|
+
.assert.urlContains(adminListUrl);
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// TODO: Update once flask has been updated on the server
|
|
84
|
+
// "attempt to view a book page before signing in": (browser) => {
|
|
85
|
+
// const { adminBookUrl, bookTitle } = getAdminBookUrlAndTitle(body, browser);
|
|
86
|
+
// const { username, password, submit } = loginPage.elements;
|
|
87
|
+
// const { bookTitleSelector } = browser.page.book().elements;
|
|
88
|
+
|
|
89
|
+
// browser
|
|
90
|
+
// .url(adminBookUrl)
|
|
91
|
+
// .waitForElementVisible(username, 1000)
|
|
92
|
+
// .verify.urlContains("redirect=" + encodeURIComponent(adminBookUrl))
|
|
93
|
+
// .setValue(username, browser.globals.username)
|
|
94
|
+
// .setValue(password, browser.globals.password)
|
|
95
|
+
// .click(submit)
|
|
96
|
+
// .waitForElementVisible(loadingSelector, 1000)
|
|
97
|
+
// .verify.containsText(bookTitleSelector, bookTitle)
|
|
98
|
+
// .assert.urlContains(adminBookUrl);
|
|
99
|
+
// },
|
|
100
|
+
|
|
101
|
+
afterEach: (browser) => {
|
|
102
|
+
browser.end();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The log in error page contains a simple message and a link to go back
|
|
5
|
+
* to the log in page.
|
|
6
|
+
*/
|
|
7
|
+
"go to the error page with bad log in credentials": (browser) => {
|
|
8
|
+
const errorMessage = "p";
|
|
9
|
+
const tryAgainButton = "a";
|
|
10
|
+
|
|
11
|
+
browser
|
|
12
|
+
.resizeWindow(1200, 900)
|
|
13
|
+
.signIn("bad email", "bad password")
|
|
14
|
+
.waitForElementVisible("body", 10000)
|
|
15
|
+
.expect.element(errorMessage).text.to.contain("401 ERROR");
|
|
16
|
+
|
|
17
|
+
browser
|
|
18
|
+
.assert.attributeContains(tryAgainButton, "href", "/admin/sign_in");
|
|
19
|
+
|
|
20
|
+
browser.end();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Jest Unit Tests
|
|
2
|
+
|
|
3
|
+
This directory contains unit tests that run using jest. The directory structure should mirror that of the `src` tree.
|
|
4
|
+
|
|
5
|
+
To run these tests, use the command `npm run test-jest`. These tests are executed along with the older mocha-based tests when `npm test` is run.
|
|
6
|
+
To run a single test file, use the command `npm run test-jest-file [filename]`.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_BASE_ENDPOINT_URL,
|
|
3
|
+
getInventoryReportInfo,
|
|
4
|
+
requestInventoryReport,
|
|
5
|
+
} from "../../../src/api/admin";
|
|
6
|
+
import * as fetchMock from "fetch-mock-jest";
|
|
7
|
+
|
|
8
|
+
const sampleInfoResponseData = { collections: [] };
|
|
9
|
+
const sampleGenerateResponseData = { message: "some message" };
|
|
10
|
+
|
|
11
|
+
const testAlternateBaseUrl = "/test/base/url";
|
|
12
|
+
const libraryKey = "short-name";
|
|
13
|
+
|
|
14
|
+
const testEndpoints = ({
|
|
15
|
+
title,
|
|
16
|
+
baseEndpointUrl: baseEndpointUrl = undefined,
|
|
17
|
+
expectedUrl = DEFAULT_BASE_ENDPOINT_URL,
|
|
18
|
+
}) => {
|
|
19
|
+
describe(title, () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
fetchMock
|
|
22
|
+
.get("*", { body: sampleInfoResponseData, status: 200 })
|
|
23
|
+
.post("*", { body: sampleGenerateResponseData, status: 202 });
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
fetchMock.mockReset();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("requests inventory report information", async () => {
|
|
31
|
+
const response = await getInventoryReportInfo({
|
|
32
|
+
library: libraryKey,
|
|
33
|
+
baseEndpointUrl,
|
|
34
|
+
});
|
|
35
|
+
expect(response).toStrictEqual(sampleInfoResponseData);
|
|
36
|
+
expect(fetchMock).toHaveBeenCalledWith(expectedUrl);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("requests report generation via a post to the endpoint", async () => {
|
|
40
|
+
const response = await requestInventoryReport({
|
|
41
|
+
library: libraryKey,
|
|
42
|
+
baseEndpointUrl,
|
|
43
|
+
});
|
|
44
|
+
expect(response).toStrictEqual(sampleGenerateResponseData);
|
|
45
|
+
expect(fetchMock).toHaveBeenCalledWith(expectedUrl, { method: "POST" });
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
describe("Inventory report API", () => {
|
|
51
|
+
testEndpoints({
|
|
52
|
+
title: "default endpoints",
|
|
53
|
+
expectedUrl: `${DEFAULT_BASE_ENDPOINT_URL}/${libraryKey}`,
|
|
54
|
+
});
|
|
55
|
+
testEndpoints({
|
|
56
|
+
title: "alternative test endpoints",
|
|
57
|
+
baseEndpointUrl: testAlternateBaseUrl,
|
|
58
|
+
expectedUrl: `${testAlternateBaseUrl}/${libraryKey}`,
|
|
59
|
+
});
|
|
60
|
+
});
|