Skip to content

Commit e36f9e3

Browse files
authored
FAT-26319 Firebird - Create Cypress test - Verify correct display of Arabic characters in Instance editable text fields in EXCEL .csv files downloaded from Bulk edit (#7192)
1 parent 8bf41e7 commit e36f9e3

6 files changed

Lines changed: 232 additions & 1 deletion

File tree

cypress.config.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,20 @@ module.exports = defineConfig({
154154
return converter.csv2json(data, options);
155155
},
156156

157+
parseExcelCsvFile(filePath) {
158+
// eslint-disable-next-line global-require
159+
const XLSX = require('xlsx');
160+
const fileBuffer = fs.readFileSync(filePath);
161+
const hasBom = fileBuffer[0] === 0xef && fileBuffer[1] === 0xbb && fileBuffer[2] === 0xbf;
162+
// Strip BOM before parsing: xlsx v0.18.x prepends the BOM character
163+
// to the first column header when given a BOM-prefixed buffer
164+
const parseBuffer = hasBom ? fileBuffer.slice(3) : fileBuffer;
165+
const workbook = XLSX.read(parseBuffer, { type: 'buffer', codepage: 65001 });
166+
const sheet = workbook.Sheets[workbook.SheetNames[0]];
167+
const rows = XLSX.utils.sheet_to_json(sheet, { defval: '' });
168+
return { hasBom, rows };
169+
},
170+
157171
downloadFile,
158172

159173
deleteFolder(folderName) {
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import { BULK_EDIT_TABLE_COLUMN_HEADERS } from '../../../support/constants';
2+
import permissions from '../../../support/dictionary/permissions';
3+
import BulkEditActions from '../../../support/fragments/bulk-edit/bulk-edit-actions';
4+
import BulkEditFiles from '../../../support/fragments/bulk-edit/bulk-edit-files';
5+
import BulkEditSearchPane from '../../../support/fragments/bulk-edit/bulk-edit-search-pane';
6+
import InventoryInstance from '../../../support/fragments/inventory/inventoryInstance';
7+
import TopMenu from '../../../support/fragments/topMenu';
8+
import Users from '../../../support/fragments/users/users';
9+
import FileManager from '../../../support/utils/fileManager';
10+
import getRandomPostfix from '../../../support/utils/stringTools';
11+
12+
let user;
13+
const arabicText = 'هذا اختبار';
14+
const instanceUUIDsFileName = `instanceUUIDs_C651597_${getRandomPostfix()}.csv`;
15+
const instance = {
16+
title: `C651597_AT_${getRandomPostfix()} ${arabicText}`,
17+
indexTitle: `${arabicText}_${getRandomPostfix()}`,
18+
};
19+
const matchedRecordsFileName = BulkEditFiles.getMatchedRecordsFileName(instanceUUIDsFileName);
20+
const previewFileName = BulkEditFiles.getPreviewFileName(instanceUUIDsFileName);
21+
const changedRecordsFileName = BulkEditFiles.getChangedRecordsFileName(instanceUUIDsFileName);
22+
23+
const arabicColumns = [
24+
{
25+
header: BULK_EDIT_TABLE_COLUMN_HEADERS.INVENTORY_INSTANCES.RESOURCE_TITLE,
26+
value: arabicText,
27+
},
28+
{
29+
header: BULK_EDIT_TABLE_COLUMN_HEADERS.INVENTORY_INSTANCES.INDEX_TITLE,
30+
value: arabicText,
31+
},
32+
{
33+
header: BULK_EDIT_TABLE_COLUMN_HEADERS.INVENTORY_INSTANCES.ADMINISTRATIVE_NOTE,
34+
value: arabicText,
35+
},
36+
];
37+
38+
describe('Bulk-edit', () => {
39+
describe('In-app approach', () => {
40+
before('create test data', () => {
41+
cy.createTempUser([
42+
permissions.bulkEditEdit.gui,
43+
permissions.uiInventoryViewCreateEditInstances.gui,
44+
]).then((userProperties) => {
45+
user = userProperties;
46+
cy.getAdminToken();
47+
cy.getInstanceTypes({ limit: 1 })
48+
.then((instanceTypes) => {
49+
instance.instanceTypeId = instanceTypes[0].id;
50+
})
51+
.then(() => {
52+
cy.createInstance({
53+
instance: {
54+
instanceTypeId: instance.instanceTypeId,
55+
title: instance.title,
56+
indexTitle: instance.indexTitle,
57+
administrativeNotes: [arabicText],
58+
},
59+
}).then((instanceId) => {
60+
instance.id = instanceId;
61+
FileManager.createFile(`cypress/fixtures/${instanceUUIDsFileName}`, instance.id);
62+
});
63+
});
64+
cy.login(user.username, user.password, {
65+
path: TopMenu.bulkEditPath,
66+
waiter: BulkEditSearchPane.waitLoading,
67+
});
68+
});
69+
});
70+
71+
after('delete test data', () => {
72+
cy.getAdminToken();
73+
InventoryInstance.deleteInstanceViaApi(instance.id);
74+
Users.deleteViaApi(user.userId);
75+
FileManager.deleteFile(`cypress/fixtures/${instanceUUIDsFileName}`);
76+
FileManager.deleteFileFromDownloadsByMask(
77+
matchedRecordsFileName,
78+
previewFileName,
79+
changedRecordsFileName,
80+
);
81+
});
82+
83+
it(
84+
'C651597 Verify correct display of Arabic characters in Instance editable text fields in EXCEL .csv files downloaded from Bulk edit (firebird)',
85+
{ tags: ['extendedPath', 'firebird', 'C651597'] },
86+
() => {
87+
// Steps 1-3: Upload UUID file and verify matched results
88+
BulkEditSearchPane.verifyDragNDropRecordTypeIdentifierArea('Instance', 'Instance UUIDs');
89+
BulkEditSearchPane.uploadFile(instanceUUIDsFileName);
90+
BulkEditSearchPane.checkForUploading(instanceUUIDsFileName);
91+
BulkEditSearchPane.waitFileUploading();
92+
BulkEditSearchPane.verifySpecificItemsMatched(arabicText);
93+
94+
// Steps 4-5: Download matched records CSV and verify Arabic text + UTF-8 BOM
95+
BulkEditActions.downloadMatchedResults();
96+
BulkEditFiles.verifyBomAndArabicColumnsInCsvFile(
97+
matchedRecordsFileName,
98+
instance.id,
99+
arabicColumns,
100+
);
101+
102+
// Steps 6-7: Open FOLIO Instances form, set Staff suppress to true
103+
BulkEditActions.openStartBulkEditFolioInstanceForm();
104+
BulkEditActions.selectOption('Staff suppress');
105+
BulkEditActions.selectAction('Set true');
106+
107+
// Step 8: Confirm changes
108+
BulkEditActions.confirmChanges();
109+
BulkEditActions.verifyMessageBannerInAreYouSureForm(1);
110+
111+
// Steps 9-10: Download preview CSV and verify Arabic text + UTF-8 BOM
112+
BulkEditActions.downloadPreview();
113+
BulkEditFiles.verifyBomAndArabicColumnsInCsvFile(
114+
previewFileName,
115+
instance.id,
116+
arabicColumns,
117+
);
118+
119+
// Step 11: Commit changes
120+
BulkEditActions.commitChanges();
121+
BulkEditSearchPane.waitFileUploading();
122+
BulkEditActions.verifySuccessBanner(1);
123+
124+
// Steps 12-13: Download changed records CSV and verify Arabic text + UTF-8 BOM
125+
BulkEditActions.openActions();
126+
BulkEditActions.downloadChangedCSV();
127+
BulkEditFiles.verifyBomAndArabicColumnsInCsvFile(
128+
changedRecordsFileName,
129+
instance.id,
130+
arabicColumns,
131+
);
132+
},
133+
);
134+
});
135+
});

cypress/support/fragments/bulk-edit/bulk-edit-files.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable no-unused-expressions */
2+
import { BULK_EDIT_TABLE_COLUMN_HEADERS } from '../../constants';
23
import FileManager from '../../utils/fileManager';
34
import DateTools from '../../utils/dateTools';
45

@@ -365,6 +366,19 @@ export default {
365366
});
366367
},
367368

369+
verifyBomAndArabicColumnsInCsvFile(fileNameMask, instanceUUID, columnsToVerify) {
370+
return FileManager.parseExcelCsvFile(fileNameMask).then(({ hasBom, rows }) => {
371+
expect(hasBom, 'File must have UTF-8 BOM for correct Excel display').to.be.true;
372+
const row = rows.find(
373+
(r) => r[BULK_EDIT_TABLE_COLUMN_HEADERS.INVENTORY_INSTANCES.INSTANCE_UUID] === instanceUUID,
374+
);
375+
expect(row, `Row with Instance UUID "${instanceUUID}" must exist in CSV`).to.exist;
376+
columnsToVerify.forEach(({ header, value }) => {
377+
expect(row[header], `Column "${header}" must contain Arabic text`).to.include(value);
378+
});
379+
});
380+
},
381+
368382
verifyColumnHeaderExistsInCsvFile(fileName, columnHeaders) {
369383
FileManager.findDownloadedFilesByMask(fileName).then((downloadedFilenames) => {
370384
if (!downloadedFilenames || downloadedFilenames.length === 0) {

cypress/support/utils/fileManager.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ export default {
7070
return cy.get('@jsonData');
7171
},
7272

73+
parseExcelCsvFile(fileNameMask) {
74+
cy.wait(Cypress.env('downloadTimeout'));
75+
76+
return this.findDownloadedFilesByMask(fileNameMask).then((downloadedFileNames) => {
77+
const lastDownloadedFileName = downloadedFileNames.sort()[downloadedFileNames.length - 1];
78+
return cy.task('parseExcelCsvFile', lastDownloadedFileName);
79+
});
80+
},
81+
7382
writeToSeparateFile({ readFileName, writeFileName, lines = [] } = {}) {
7483
cy.wait(Cypress.env('downloadTimeout'));
7584

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@
8585
"prettier": "^3.0.2",
8686
"tsx": "3.14.0",
8787
"uuid": "^3.4.0",
88-
"webpack": "^5.94.0"
88+
"webpack": "^5.94.0",
89+
"xlsx": "^0.18.5"
8990
},
9091
"publishConfig": {
9192
"registry": "https://repository.folio.org/repository/npm-folio/"

yarn.lock

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3202,6 +3202,11 @@ add-asset-html-webpack-plugin@^6.0.0:
32023202
globby "^11.1.0"
32033203
micromatch "^4.0.4"
32043204

3205+
adler-32@~1.3.0:
3206+
version "1.3.1"
3207+
resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2"
3208+
integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==
3209+
32053210
adm-zip@^0.5.10:
32063211
version "0.5.16"
32073212
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.16.tgz#0b5e4c779f07dedea5805cdccb1147071d94a909"
@@ -4069,6 +4074,14 @@ caseless@~0.12.0:
40694074
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
40704075
integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
40714076

4077+
cfb@~1.2.1:
4078+
version "1.2.2"
4079+
resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44"
4080+
integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==
4081+
dependencies:
4082+
adler-32 "~1.3.0"
4083+
crc-32 "~1.2.0"
4084+
40724085
chalk@3.0.0:
40734086
version "3.0.0"
40744087
resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
@@ -4256,6 +4269,11 @@ clone@^1.0.2:
42564269
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
42574270
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
42584271

4272+
codepage@~1.15.0:
4273+
version "1.15.0"
4274+
resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab"
4275+
integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==
4276+
42594277
coffee-loader@^4.0.0:
42604278
version "4.0.0"
42614279
resolved "https://registry.yarnpkg.com/coffee-loader/-/coffee-loader-4.0.0.tgz#85284b489b0a63963da2b52e372111edf0565617"
@@ -4522,6 +4540,11 @@ cosmiconfig@^8.1.3, cosmiconfig@^8.3.5:
45224540
parse-json "^5.2.0"
45234541
path-type "^4.0.0"
45244542

4543+
crc-32@~1.2.0, crc-32@~1.2.1:
4544+
version "1.2.2"
4545+
resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff"
4546+
integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
4547+
45254548
create-ecdh@^4.0.4:
45264549
version "4.0.4"
45274550
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
@@ -6456,6 +6479,11 @@ forwarded@0.2.0:
64566479
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
64576480
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
64586481

6482+
frac@~1.1.2:
6483+
version "1.1.2"
6484+
resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b"
6485+
integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==
6486+
64596487
fraction.js@^5.3.4:
64606488
version "5.3.4"
64616489
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-5.3.4.tgz#8c0fcc6a9908262df4ed197427bdeef563e0699a"
@@ -10264,6 +10292,13 @@ sprintf-js@~1.0.2:
1026410292
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
1026510293
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
1026610294

10295+
ssf@~0.11.2:
10296+
version "0.11.2"
10297+
resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c"
10298+
integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==
10299+
dependencies:
10300+
frac "~1.1.2"
10301+
1026710302
sshpk@^1.14.1, sshpk@^1.7.0:
1026810303
version "1.18.0"
1026910304
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028"
@@ -11428,11 +11463,21 @@ which@^2.0.1:
1142811463
dependencies:
1142911464
isexe "^2.0.0"
1143011465

11466+
wmf@~1.0.1:
11467+
version "1.0.2"
11468+
resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da"
11469+
integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==
11470+
1143111471
word-wrap@^1.2.5:
1143211472
version "1.2.5"
1143311473
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
1143411474
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
1143511475

11476+
word@~0.3.0:
11477+
version "0.3.0"
11478+
resolved "https://registry.yarnpkg.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961"
11479+
integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==
11480+
1143611481
wordwrap@^1.0.0:
1143711482
version "1.0.0"
1143811483
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
@@ -11497,6 +11542,19 @@ wsl-utils@^0.1.0:
1149711542
dependencies:
1149811543
is-wsl "^3.1.0"
1149911544

11545+
xlsx@^0.18.5:
11546+
version "0.18.5"
11547+
resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0"
11548+
integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==
11549+
dependencies:
11550+
adler-32 "~1.3.0"
11551+
cfb "~1.2.1"
11552+
codepage "~1.15.0"
11553+
crc-32 "~1.2.1"
11554+
ssf "~0.11.2"
11555+
wmf "~1.0.1"
11556+
word "~0.3.0"
11557+
1150011558
xml2js@^0.6.1:
1150111559
version "0.6.2"
1150211560
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499"

0 commit comments

Comments
 (0)