View | Details | Raw Unified | Return to bug 40170
Collapse All | Expand All

(-)a/cypress.config.ts (-8 lines)
Lines 15-27 export default defineConfig({ Link Here
15
        baseUrl: "http://localhost:8081",
15
        baseUrl: "http://localhost:8081",
16
        specPattern: "t/cypress/integration/**/*.*",
16
        specPattern: "t/cypress/integration/**/*.*",
17
        supportFile: "t/cypress/support/e2e.js",
17
        supportFile: "t/cypress/support/e2e.js",
18
        env: {
19
            db: {
20
                host: "db",
21
                user: "koha_kohadev",
22
                password: "password",
23
                database: "koha_kohadev",
24
            },
25
        },
26
    },
18
    },
27
});
19
});
(-)a/package.json (-1 / +1 lines)
Lines 19-25 Link Here
19
    "bootstrap": "^5.3.3",
19
    "bootstrap": "^5.3.3",
20
    "css-loader": "^6.6.0",
20
    "css-loader": "^6.6.0",
21
    "cypress": "^12.17.2",
21
    "cypress": "^12.17.2",
22
    "cypress-mysql": "^1.0.0",
23
    "datatables.net-buttons": "^2.3.4",
22
    "datatables.net-buttons": "^2.3.4",
24
    "datatables.net-vue3": "^2.0.0",
23
    "datatables.net-vue3": "^2.0.0",
25
    "gulp": "^4.0.2",
24
    "gulp": "^4.0.2",
Lines 82-87 Link Here
82
    "globals": "^16.0.0",
81
    "globals": "^16.0.0",
83
    "gulp-tap": "^1.0.1",
82
    "gulp-tap": "^1.0.1",
84
    "html-webpack-plugin": "^5.5.0",
83
    "html-webpack-plugin": "^5.5.0",
84
    "mysql2": "^3.14.1",
85
    "node-sass-tilde-importer": "^1.0.2",
85
    "node-sass-tilde-importer": "^1.0.2",
86
    "postcss": "^8.4.14",
86
    "postcss": "^8.4.14",
87
    "postcss-selector-parser": "^6.0.10",
87
    "postcss-selector-parser": "^6.0.10",
(-)a/t/cypress/integration/Auth/csrf.ts (-33 / +33 lines)
Lines 5-11 const branchname = "test_branchname"; Link Here
5
5
6
function cleanup() {
6
function cleanup() {
7
    const sql = "DELETE FROM branches WHERE branchcode=?";
7
    const sql = "DELETE FROM branches WHERE branchcode=?";
8
    cy.query(sql, branchcode);
8
    cy.task("query", { sql, values: [branchcode] });
9
}
9
}
10
10
11
describe("CSRF", () => {
11
describe("CSRF", () => {
Lines 32-41 describe("CSRF", () => { Link Here
32
            .find(".alert")
32
            .find(".alert")
33
            .contains(/No CSRF token passed for POST/);
33
            .contains(/No CSRF token passed for POST/);
34
34
35
        cy.query(
35
        cy.task("query", {
36
            "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
36
            sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
37
            branchcode
37
            values: [branchcode],
38
        ).then(result => {
38
        }).then(result => {
39
            expect(result[0].count).to.equal(0);
39
            expect(result[0].count).to.equal(0);
40
        });
40
        });
41
    });
41
    });
Lines 53-62 describe("CSRF", () => { Link Here
53
            .find(".alert")
53
            .find(".alert")
54
            .contains(/Wrong CSRF token/);
54
            .contains(/Wrong CSRF token/);
55
55
56
        cy.query(
56
        cy.task("query", {
57
            "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
57
            sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
58
            branchcode
58
            values: [branchcode],
59
        ).then(result => {
59
        }).then(result => {
60
            expect(result[0].count).to.equal(0);
60
            expect(result[0].count).to.equal(0);
61
        });
61
        });
62
    });
62
    });
Lines 89-98 describe("CSRF", () => { Link Here
89
        // We do not want Wrong CSRF token here
89
        // We do not want Wrong CSRF token here
90
        cy.get(".message").should("not.exist");
90
        cy.get(".message").should("not.exist");
91
91
92
        cy.query(
92
        cy.task("query", {
93
            "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
93
            sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
94
            branchcode
94
            values: [branchcode],
95
        ).then(result => {
95
        }).then(result => {
96
            expect(result[0].count).to.equal(0);
96
            expect(result[0].count).to.equal(0);
97
        });
97
        });
98
    });
98
    });
Lines 112-130 describe("CSRF", () => { Link Here
112
        cy.get("select[name='libraries_length']").select("-1");
112
        cy.get("select[name='libraries_length']").select("-1");
113
        cy.get("td").contains(branchcode);
113
        cy.get("td").contains(branchcode);
114
114
115
        cy.query(
115
        cy.task("query", {
116
            "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
116
            sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
117
            branchcode
117
            values: [branchcode],
118
        ).then(result => {
118
        }).then(result => {
119
            expect(result[0].count).to.equal(1);
119
            expect(result[0].count).to.equal(1);
120
        });
120
        });
121
    });
121
    });
122
122
123
    it("Delete without CSRF", () => {
123
    it("Delete without CSRF", () => {
124
        cy.query("INSERT INTO branches(branchcode, branchname) VALUES (?, ?)", [
124
        cy.task("query", {
125
            branchcode,
125
            sql: "INSERT INTO branches(branchcode, branchname) VALUES (?, ?)",
126
            branchname,
126
            values: [branchcode, branchname],
127
        ]);
127
        });
128
128
129
        cy.visit("/cgi-bin/koha/admin/branches.pl");
129
        cy.visit("/cgi-bin/koha/admin/branches.pl");
130
        cy.get("select[name='libraries_length']").select("-1");
130
        cy.get("select[name='libraries_length']").select("-1");
Lines 141-159 describe("CSRF", () => { Link Here
141
            .find(".alert")
141
            .find(".alert")
142
            .contains(/No CSRF token passed for POST/);
142
            .contains(/No CSRF token passed for POST/);
143
143
144
        cy.query(
144
        cy.task("query", {
145
            "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
145
            sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
146
            branchcode
146
            values: [branchcode],
147
        ).then(result => {
147
        }).then(result => {
148
            expect(result[0].count).to.equal(1);
148
            expect(result[0].count).to.equal(1);
149
        });
149
        });
150
    });
150
    });
151
151
152
    it("Delete", () => {
152
    it("Delete", () => {
153
        cy.query("INSERT INTO branches(branchcode, branchname) VALUES (?, ?)", [
153
        cy.task("query", {
154
            branchcode,
154
            sql: "INSERT INTO branches(branchcode, branchname) VALUES (?, ?)",
155
            branchname,
155
            values: [branchcode, branchname],
156
        ]);
156
        });
157
157
158
        cy.visit("/cgi-bin/koha/admin/branches.pl");
158
        cy.visit("/cgi-bin/koha/admin/branches.pl");
159
        cy.get("select[name='libraries_length']").select("-1");
159
        cy.get("select[name='libraries_length']").select("-1");
Lines 165-174 describe("CSRF", () => { Link Here
165
            .find(".alert")
165
            .find(".alert")
166
            .contains(/Library deleted successfully/);
166
            .contains(/Library deleted successfully/);
167
167
168
        cy.query(
168
        cy.task("query", {
169
            "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
169
            sql: "SELECT COUNT(*) as count FROM branches WHERE branchcode=?",
170
            branchcode
170
            values: [branchcode],
171
        ).then(result => {
171
        }).then(result => {
172
            expect(result[0].count).to.equal(0);
172
            expect(result[0].count).to.equal(0);
173
        });
173
        });
174
    });
174
    });
(-)a/t/cypress/integration/Islands/AcquisitionsMenu_spec.ts (-4 / +6 lines)
Lines 23-34 describe("Acquisitions menu", () => { Link Here
23
    it("Should show/hide links based on permissions", () => {
23
    it("Should show/hide links based on permissions", () => {
24
        cy.get(".sidebar_menu").should("be.visible");
24
        cy.get(".sidebar_menu").should("be.visible");
25
25
26
        cy.query(
26
        cy.task("query", {
27
            "UPDATE borrowers SET flags=2052 WHERE borrowernumber=51"
27
            sql: "UPDATE borrowers SET flags=2052 WHERE borrowernumber=51",
28
        ).then(() => {
28
        }).then(() => {
29
            cy.reload(true);
29
            cy.reload(true);
30
            cy.get(".sidebar_menu a").should("have.length", 8);
30
            cy.get(".sidebar_menu a").should("have.length", 8);
31
            cy.query("UPDATE borrowers SET flags=1 WHERE borrowernumber=51");
31
            cy.task("query", {
32
                sql: "UPDATE borrowers SET flags=1 WHERE borrowernumber=51",
33
            });
32
        });
34
        });
33
    });
35
    });
34
    it("Should correctly apply the 'current' class", () => {
36
    it("Should correctly apply the 'current' class", () => {
(-)a/t/cypress/integration/KohaTable/Holdings_spec.ts (-10 / +14 lines)
Lines 42-48 describe("catalogue/detail/holdings_table with items", () => { Link Here
42
                cy.wrap(Promise.resolve())
42
                cy.wrap(Promise.resolve())
43
                    .then(() => {
43
                    .then(() => {
44
                        return queries.reduce((chain, { query, values }) => {
44
                        return queries.reduce((chain, { query, values }) => {
45
                            return chain.then(() => cy.query(query, values));
45
                            return chain.then(() =>
46
                                cy.task("query", { sql: query, values })
47
                            );
46
                        }, Promise.resolve());
48
                        }, Promise.resolve());
47
                    })
49
                    })
48
                    .then(() => {
50
                    .then(() => {
Lines 102-110 describe("catalogue/detail/holdings_table with items", () => { Link Here
102
                        });
104
                        });
103
                    });
105
                    });
104
            });
106
            });
105
        cy.query(
107
        cy.task("query", {
106
            "SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'"
108
            sql: "SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'",
107
        ).then(value => {
109
        }).then(value => {
108
            cy.wrap(value).as("syspref_AlwaysShowHoldingsTableFilters");
110
            cy.wrap(value).as("syspref_AlwaysShowHoldingsTableFilters");
109
        });
111
        });
110
    });
112
    });
Lines 435-448 describe("catalogue/detail/holdings_table without items", () => { Link Here
435
                const item_type = generated_objects["item_type"];
437
                const item_type = generated_objects["item_type"];
436
                const queries = [
438
                const queries = [
437
                    {
439
                    {
438
                        query: "INSERT INTO itemtypes(itemtype, description) VALUES (?, ?)",
440
                        sql: "INSERT INTO itemtypes(itemtype, description) VALUES (?, ?)",
439
                        values: [item_type.item_type_id, item_type.description],
441
                        values: [item_type.item_type_id, item_type.description],
440
                    },
442
                    },
441
                ];
443
                ];
442
                cy.wrap(Promise.resolve())
444
                cy.wrap(Promise.resolve())
443
                    .then(() => {
445
                    .then(() => {
444
                        return queries.reduce((chain, { query, values }) => {
446
                        return queries.reduce((chain, { sql, values }) => {
445
                            return chain.then(() => cy.query(query, values));
447
                            return chain.then(() =>
448
                                cy.task("query", { sql, values })
449
                            );
446
                        }, Promise.resolve());
450
                        }, Promise.resolve());
447
                    })
451
                    })
448
                    .then(() => {
452
                    .then(() => {
Lines 491-499 describe("catalogue/detail/holdings_table without items", () => { Link Here
491
                        });
495
                        });
492
                    });
496
                    });
493
            });
497
            });
494
        cy.query(
498
        cy.task("query", {
495
            "SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'"
499
            sql: "SELECT value FROM systempreferences WHERE variable='AlwaysShowHoldingsTableFilters'",
496
        ).then(value => {
500
        }).then(value => {
497
            cy.wrap(value).as("syspref_AlwaysShowHoldingsTableFilters");
501
            cy.wrap(value).as("syspref_AlwaysShowHoldingsTableFilters");
498
        });
502
        });
499
    });
503
    });
(-)a/t/cypress/integration/KohaTable/PatronSearch_spec.ts (-18 / +18 lines)
Lines 9-15 const patron_attr_type = "attribute_type4TEST"; Link Here
9
9
10
function cleanup() {
10
function cleanup() {
11
    const sql = "DELETE FROM borrower_attribute_types WHERE code=?";
11
    const sql = "DELETE FROM borrower_attribute_types WHERE code=?";
12
    cy.query(sql, patron_attr_type);
12
    cy.task("query", { sql, values: [patron_attr_type] });
13
}
13
}
14
describe("ExtendedPatronAttributes", () => {
14
describe("ExtendedPatronAttributes", () => {
15
    beforeEach(() => {
15
    beforeEach(() => {
Lines 19-27 describe("ExtendedPatronAttributes", () => { Link Here
19
        cy.window().then(win => {
19
        cy.window().then(win => {
20
            win.localStorage.clear();
20
            win.localStorage.clear();
21
        });
21
        });
22
        cy.query(
22
        cy.task("query", {
23
            "SELECT value FROM systempreferences WHERE variable='ExtendedPatronAttributes'"
23
            sql: "SELECT value FROM systempreferences WHERE variable='ExtendedPatronAttributes'",
24
        ).then(value => {
24
        }).then(value => {
25
            cy.wrap(value).as("syspref_ExtendedPatronAttributes");
25
            cy.wrap(value).as("syspref_ExtendedPatronAttributes");
26
        });
26
        });
27
    });
27
    });
Lines 45-53 describe("ExtendedPatronAttributes", () => { Link Here
45
            cy.get("#search_patron_filter").type("something");
45
            cy.get("#search_patron_filter").type("something");
46
            cy.get("form.patron_search_form input[type='submit']").click();
46
            cy.get("form.patron_search_form input[type='submit']").click();
47
47
48
            cy.query(
48
            cy.task("query", {
49
                "select count(*) as nb_searchable from borrower_attribute_types where staff_searchable=1"
49
                sql: "select count(*) as nb_searchable from borrower_attribute_types where staff_searchable=1",
50
            ).then(result => {
50
            }).then(result => {
51
                const has_searchable = result[0].nb_searchable;
51
                const has_searchable = result[0].nb_searchable;
52
                cy.wait("@searchPatrons").then(interception => {
52
                cy.wait("@searchPatrons").then(interception => {
53
                    const q = interception.request.query.q;
53
                    const q = interception.request.query.q;
Lines 55-64 describe("ExtendedPatronAttributes", () => { Link Here
55
                });
55
                });
56
            });
56
            });
57
57
58
            cy.query(
58
            cy.task("query", {
59
                "INSERT INTO borrower_attribute_types(code, description, staff_searchable, searched_by_default) VALUES (?, 'only for tests', 1, 1)",
59
                sql: "INSERT INTO borrower_attribute_types(code, description, staff_searchable, searched_by_default) VALUES (?, 'only for tests', 1, 1)",
60
                patron_attr_type
60
                values: [patron_attr_type],
61
            ).then(() => {
61
            }).then(() => {
62
                cy.visit("/cgi-bin/koha/members/members-home.pl");
62
                cy.visit("/cgi-bin/koha/members/members-home.pl");
63
63
64
                cy.get("#search_patron_filter").type("something");
64
                cy.get("#search_patron_filter").type("something");
Lines 80-88 describe("ExtendedPatronAttributes", () => { Link Here
80
            cy.get("#search_patron_filter").type("something");
80
            cy.get("#search_patron_filter").type("something");
81
            cy.get("form.patron_search_form input[type='submit']").click();
81
            cy.get("form.patron_search_form input[type='submit']").click();
82
82
83
            cy.query(
83
            cy.task("query", {
84
                "select count(*) as nb_searchable from borrower_attribute_types where staff_searchable=1 AND searched_by_default=1"
84
                sql: "select count(*) as nb_searchable from borrower_attribute_types where staff_searchable=1 AND searched_by_default=1",
85
            ).then(result => {
85
            }).then(result => {
86
                const has_searchable = result[0].nb_searchable;
86
                const has_searchable = result[0].nb_searchable;
87
                cy.wait("@searchPatrons").then(interception => {
87
                cy.wait("@searchPatrons").then(interception => {
88
                    const q = interception.request.query.q;
88
                    const q = interception.request.query.q;
Lines 94-103 describe("ExtendedPatronAttributes", () => { Link Here
94
                });
94
                });
95
            });
95
            });
96
96
97
            cy.query(
97
            cy.task("query", {
98
                "INSERT INTO borrower_attribute_types(code, description, staff_searchable, searched_by_default) VALUES (?, 'only for tests', 1, 1)",
98
                sql: "INSERT INTO borrower_attribute_types(code, description, staff_searchable, searched_by_default) VALUES (?, 'only for tests', 1, 1)",
99
                patron_attr_type
99
                values: [patron_attr_type],
100
            ).then(() => {
100
            }).then(() => {
101
                cy.visit("/cgi-bin/koha/members/members-home.pl");
101
                cy.visit("/cgi-bin/koha/members/members-home.pl");
102
102
103
                cy.get("#search_patron_filter").type("something");
103
                cy.get("#search_patron_filter").type("something");
(-)a/t/cypress/integration/t/db.ts (+15 lines)
Line 0 Link Here
1
describe("DB tests", () => {
2
    it("should be able to SELECT", () => {
3
        cy.task("query", { sql: "SELECT count(*) FROM borrowers" }).then(
4
            rows => {
5
                expect(typeof rows.length).to.be.equal("number");
6
            }
7
        );
8
        cy.task("query", {
9
            sql: "SELECT count(*) FROM borrowers WHERE `surname` = ?",
10
            values: ["john"],
11
        }).then(rows => {
12
            expect(typeof rows.length).to.be.equal("number");
13
        });
14
    });
15
});
(-)a/t/cypress/plugins/db.js (+17 lines)
Line 0 Link Here
1
const mysql = require("mysql2/promise");
2
3
const connectionConfig = {
4
    host: "db",
5
    user: "koha_kohadev",
6
    password: "password",
7
    database: "koha_kohadev",
8
};
9
10
async function query(sql, params = []) {
11
    const connection = await mysql.createConnection(connectionConfig);
12
    const [rows] = await connection.execute(sql, params);
13
    await connection.end();
14
    return rows;
15
}
16
17
module.exports = { query };
(-)a/t/cypress/plugins/index.js (-4 / +3 lines)
Lines 1-9 Link Here
1
const { startDevServer } = require("@cypress/webpack-dev-server");
1
const { startDevServer } = require("@cypress/webpack-dev-server");
2
2
3
const mysql = require("cypress-mysql");
4
5
const { buildSampleObject, buildSampleObjects } = require("./mockData.js");
3
const { buildSampleObject, buildSampleObjects } = require("./mockData.js");
6
4
5
const { query } = require("./db.js");
6
7
module.exports = (on, config) => {
7
module.exports = (on, config) => {
8
    on("dev-server:start", options =>
8
    on("dev-server:start", options =>
9
        startDevServer({
9
        startDevServer({
Lines 11-21 module.exports = (on, config) => { Link Here
11
        })
11
        })
12
    );
12
    );
13
13
14
    mysql.configurePlugin(on);
15
16
    on("task", {
14
    on("task", {
17
        buildSampleObject,
15
        buildSampleObject,
18
        buildSampleObjects,
16
        buildSampleObjects,
17
        query,
19
    });
18
    });
20
    return config;
19
    return config;
21
};
20
};
(-)a/t/cypress/support/e2e.js (-4 lines)
Lines 1874-1882 cy.getVendor = () => { Link Here
1874
    };
1874
    };
1875
};
1875
};
1876
1876
1877
const mysql = require("cypress-mysql");
1878
mysql.addCommands();
1879
1880
Cypress.Commands.add("set_syspref", (variable, value) => {
1877
Cypress.Commands.add("set_syspref", (variable, value) => {
1881
    cy.window().then(win => {
1878
    cy.window().then(win => {
1882
        const client = win.APIClient.sysprefs;
1879
        const client = win.APIClient.sysprefs;
1883
- 

Return to bug 40170