|
1 | 1 | import { hash } from "bcrypt-ts"; |
| 2 | +import Client from "@blink.so/api"; |
2 | 3 | import { afterEach, beforeEach, expect, test } from "bun:test"; |
3 | 4 | import { http, HttpResponse } from "msw"; |
4 | 5 | import { setupServer, SetupServerApi } from "msw/node"; |
@@ -1549,3 +1550,104 @@ test("POST /verify-email rejects suspended user", async () => { |
1549 | 1550 | const data = (await res.json()) as { error: string }; |
1550 | 1551 | expect(data.error).toBe("Your account has been suspended"); |
1551 | 1552 | }); |
| 1553 | + |
| 1554 | +// Change password tests |
| 1555 | + |
| 1556 | +const changePasswordTestCases = [ |
| 1557 | + { |
| 1558 | + name: "successfully changes password", |
| 1559 | + hasPassword: true, |
| 1560 | + currentPassword: "oldpassword123", |
| 1561 | + newPassword: "newpassword456", |
| 1562 | + sendCurrentPassword: "oldpassword123", |
| 1563 | + expectedOk: true, |
| 1564 | + }, |
| 1565 | + { |
| 1566 | + name: "with wrong current password returns error", |
| 1567 | + hasPassword: true, |
| 1568 | + currentPassword: "correctpassword", |
| 1569 | + newPassword: "newpassword456", |
| 1570 | + sendCurrentPassword: "wrongpassword", |
| 1571 | + expectedError: "Current password is incorrect", |
| 1572 | + }, |
| 1573 | + { |
| 1574 | + name: "for user without password returns error", |
| 1575 | + hasPassword: false, |
| 1576 | + currentPassword: null, |
| 1577 | + newPassword: "newpassword456", |
| 1578 | + sendCurrentPassword: "anypassword", |
| 1579 | + expectedError: "Password authentication is not enabled for this account", |
| 1580 | + }, |
| 1581 | + { |
| 1582 | + name: "with short new password returns error", |
| 1583 | + hasPassword: true, |
| 1584 | + currentPassword: "oldpassword123", |
| 1585 | + newPassword: "short", |
| 1586 | + sendCurrentPassword: "oldpassword123", |
| 1587 | + expectedError: "Too small: expected string to have >=8 characters", |
| 1588 | + }, |
| 1589 | +]; |
| 1590 | + |
| 1591 | +test.each(changePasswordTestCases)( |
| 1592 | + "POST /change-password $name", |
| 1593 | + async ({ |
| 1594 | + hasPassword, |
| 1595 | + currentPassword, |
| 1596 | + newPassword, |
| 1597 | + sendCurrentPassword, |
| 1598 | + expectedOk, |
| 1599 | + expectedError, |
| 1600 | + }) => { |
| 1601 | + const { helpers, bindings } = await serve(); |
| 1602 | + const db = await bindings.database(); |
| 1603 | + |
| 1604 | + const { user, client } = await helpers.createUser({ |
| 1605 | + email: `changepass-${Date.now()}@example.com`, |
| 1606 | + }); |
| 1607 | + |
| 1608 | + await db.updateUserByID({ |
| 1609 | + id: user.id, |
| 1610 | + password: hasPassword ? await hash(currentPassword!, 10) : null, |
| 1611 | + email_verified: new Date(), |
| 1612 | + }); |
| 1613 | + |
| 1614 | + let error: string | undefined; |
| 1615 | + const data = await client.auth |
| 1616 | + .changePassword({ |
| 1617 | + currentPassword: sendCurrentPassword, |
| 1618 | + newPassword, |
| 1619 | + }) |
| 1620 | + .catch((err) => { |
| 1621 | + error = err instanceof Error ? err.message : "Unknown error"; |
| 1622 | + }); |
| 1623 | + |
| 1624 | + if (expectedOk) { |
| 1625 | + expect(data?.ok).toBe(true); |
| 1626 | + // Verify password was actually changed |
| 1627 | + const { compare } = await import("bcrypt-ts"); |
| 1628 | + const updatedUser = await db.selectUserByID(user.id); |
| 1629 | + expect(await compare(newPassword, updatedUser!.password!)).toBe(true); |
| 1630 | + } |
| 1631 | + if (expectedError) { |
| 1632 | + expect(error).toContain(expectedError); |
| 1633 | + } |
| 1634 | + } |
| 1635 | +); |
| 1636 | + |
| 1637 | +test("POST /change-password without authentication returns unauthorized error", async () => { |
| 1638 | + const { url } = await serve(); |
| 1639 | + |
| 1640 | + const client = new Client({ baseURL: url.toString() }); |
| 1641 | + |
| 1642 | + let error: string | undefined; |
| 1643 | + await client.auth |
| 1644 | + .changePassword({ |
| 1645 | + currentPassword: "oldpassword123", |
| 1646 | + newPassword: "newpassword456", |
| 1647 | + }) |
| 1648 | + .catch((err) => { |
| 1649 | + error = err instanceof Error ? err.message : "Unknown error"; |
| 1650 | + }); |
| 1651 | + |
| 1652 | + expect(error).toContain("Unauthorized"); |
| 1653 | +}); |
0 commit comments