// UserRepo test
import client from "../../../../../lambdas/shared/client";
import { User } from "../../../../../lambdas/shared/models";
import { UserRepository } from "../../../../../lambdas/shared/repositories/legacy";
import {
AiStatus,
CkaStatus,
CRSStatus,
VerificationSource,
} from "../../../../../lambdas/shared/types";
jest.mock("../../../../../lambdas/shared/client", () => ({
query: jest.fn(() => ({
records: [],
})),
beginTransaction: jest.fn(() => ({
transactionId: "mockTransactionId",
})),
commitTransaction: jest.fn(),
rollbackTransaction: jest.fn(),
}));
describe("UserRepository tests", () => {
let userRepository: UserRepository;
const mockResult = { records: [{ value: "bars" }] };
const mockQuery = jest.fn().mockResolvedValue(mockResult);
const queryExecutor = {
query: mockQuery,
};
beforeAll(() => {
userRepository = new UserRepository({ client });
});
beforeEach(() => {
jest.clearAllMocks();
});
it("should call findById", async () => {
await userRepository.findById("mockId");
expect(client.query).toHaveBeenCalledWith({
sql: `SELECT * FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id WHERE id = :userId ORDER BY u.id, k.initiated_on DESC) as us`,
parameters: [{ name: "userId", value: "mockId" }],
});
});
it("should call findAllByFilters without any filters", async () => {
await userRepository.findAllByFilters(
{},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT * FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id ORDER BY u.id, k.initiated_on DESC) as us",
[]
);
});
it("should call findAllByFilters with pagination", async () => {
await userRepository.findAllByFilters(
{ page: "1", pageSize: "50" },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT *, COUNT(*) OVER() as total_count FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id ORDER BY u.id, k.initiated_on DESC) as us ORDER BY created_at DESC LIMIT $1 OFFSET $2",
["50", 0]
);
});
it("should call findAllByFilters with name", async () => {
await userRepository.findAllByFilters(
{
page: "1",
pageSize: "50",
name: "las",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT *, COUNT(*) OVER() as total_count FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id WHERE full_name ILIKE $1 ORDER BY u.id, k.initiated_on DESC) as us ORDER BY created_at DESC LIMIT $2 OFFSET $3",
["%las%", "50", 0]
);
});
it("should call findAllByFilters with id", async () => {
await userRepository.findAllByFilters(
{
page: "1",
pageSize: "50",
id: "12",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT *, LEVENSHTEIN(id_number, $1) as id_variance, COUNT(*) OVER() as total_count FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id WHERE LEVENSHTEIN(id_number, $1) < 5 ORDER BY u.id, k.initiated_on DESC) as us ORDER BY LEVENSHTEIN(id_number, $1) ASC, created_at DESC LIMIT $2 OFFSET $3",
["12", "50", 0]
);
});
it("should call findAllByFilters with mobile", async () => {
await userRepository.findAllByFilters(
{
page: "1",
pageSize: "50",
mobile: "077",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT *, LEVENSHTEIN(mobile, $1) as mobile_variance, COUNT(*) OVER() as total_count FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id WHERE LEVENSHTEIN(mobile, $1) < 5 ORDER BY u.id, k.initiated_on DESC) as us ORDER BY LEVENSHTEIN(mobile, $1) ASC, created_at DESC LIMIT $2 OFFSET $3",
["077", "50", 0]
);
});
it("should call findAllByFilters with status", async () => {
await userRepository.findAllByFilters(
{
page: "1",
pageSize: "50",
verification_status: "POSITIVE",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT *, COUNT(*) OVER() as total_count FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id ORDER BY u.id, k.initiated_on DESC) as us WHERE us.verification_outcome = $3 ORDER BY created_at DESC LIMIT $1 OFFSET $2",
["50", 0, "POSITIVE"]
);
});
it("should call findAllByFilters with multiple statuses", async () => {
await userRepository.findAllByFilters(
{
page: "1",
pageSize: "50",
verification_status: "POSITIVE",
sanctions_status: "REJECT",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT *, COUNT(*) OVER() as total_count FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id ORDER BY u.id, k.initiated_on DESC) as us WHERE us.verification_outcome = $3 AND us.sanctions_outcome = $4 ORDER BY created_at DESC LIMIT $1 OFFSET $2",
["50", 0, "POSITIVE", "REJECT"]
);
});
it("should call findAllByFilters with name and status", async () => {
await userRepository.findAllByFilters(
{
page: "1",
pageSize: "50",
name: "las",
verification_status: "POSITIVE",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT *, COUNT(*) OVER() as total_count FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id WHERE full_name ILIKE $1 ORDER BY u.id, k.initiated_on DESC) as us WHERE us.verification_outcome = $4 ORDER BY created_at DESC LIMIT $2 OFFSET $3",
["%las%", "50", 0, "POSITIVE"]
);
});
it("should call findAllByFilters with name and mobile", async () => {
await userRepository.findAllByFilters(
{
page: "1",
pageSize: "50",
name: "las",
mobile: "077638",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT *, LEVENSHTEIN(mobile, $2) as mobile_variance, COUNT(*) OVER() as total_count FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id WHERE full_name ILIKE $1 AND LEVENSHTEIN(mobile, $2) < 5 ORDER BY u.id, k.initiated_on DESC) as us ORDER BY LEVENSHTEIN(mobile, $2) ASC, created_at DESC LIMIT $3 OFFSET $4",
["%las%", "077638", "50", 0]
);
});
it("should call findAllByFilters with name, mobile and status", async () => {
await userRepository.findAllByFilters(
{
page: "1",
pageSize: "50",
name: "las",
mobile: "077638",
verification_status: "POSITIVE",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT *, LEVENSHTEIN(mobile, $2) as mobile_variance, COUNT(*) OVER() as total_count FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id WHERE full_name ILIKE $1 AND LEVENSHTEIN(mobile, $2) < 5 ORDER BY u.id, k.initiated_on DESC) as us WHERE us.verification_outcome = $5 ORDER BY LEVENSHTEIN(mobile, $2) ASC, created_at DESC LIMIT $3 OFFSET $4",
["%las%", "077638", "50", 0, "POSITIVE"]
);
});
it("can filter by one allowed proof of address filter", async () => {
await userRepository.findAllByFilters(
{
name: "foo",
proof_of_address_status: "EXEMPT",
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT * FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id WHERE full_name ILIKE $1 ORDER BY u.id, k.initiated_on DESC) as us WHERE us.proof_of_address_outcome = $2",
["%foo%", "EXEMPT"]
);
});
it("it can filter by one allowed sanctions filter", async () => {
await userRepository.findAllByFilters(
{ sanctions_status: "ACCEPT" },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryExecutor as any,
false
);
expect(mockQuery).toHaveBeenCalledWith(
"SELECT * FROM (SELECT DISTINCT ON (u.id) * FROM users u LEFT JOIN kyc_veriff_sessions k ON u.id = k.user_id ORDER BY u.id, k.initiated_on DESC) as us WHERE us.sanctions_outcome = $1",
["ACCEPT"]
);
});
it("should call updateUser", async () => {
const user = new User({
id: "123",
isAdminUserSession: true,
});
user.date_of_birth = "2000-01-01";
user.preferred_name = "Chocolate Tester";
await userRepository.updateUser(user);
expect(client.query).toBeCalledWith({
sql: "UPDATE users SET preferred_name = :preferred_name, date_of_birth = :date_of_birth, updated_at = DEFAULT WHERE id = :userId RETURNING *",
parameters: [
{ name: "preferred_name", value: "Chocolate Tester" },
{ name: "date_of_birth", value: "2000-01-01", cast: "date" },
{ name: "userId", value: "123" },
],
});
});
it("should call updateUser with all the proper column mapping", async () => {
const user = new User({
id: "123",
isAdminUserSession: true,
});
user.full_name = "John Doe";
user.preferred_name = "John";
user.sex = "MALE";
user.mobile_country_code = "94";
user.mobile = "778212132";
user.phone_number_verified = false;
user.id_number = "93212312";
user.date_of_birth = "1990-10-05";
user.nationality = "Singaporean";
user.email = "john@gmail.com";
user.addr_line_1 = "No 4";
user.addr_line_2 = "Downing street";
user.addr_line_3 = "Yemen";
user.addr_country = "Singapore";
user.addr_postal = "231";
user.created_at = "2022-08-01";
user.updated_at = "2022-08-02";
user.cka_status = CkaStatus.NotTaken;
user.ai_status = AiStatus.NonAi;
user.crs_status = CRSStatus.unDeclared;
user.verification_source = VerificationSource.Singpass;
await userRepository.updateUser(user);
expect(client.query).toBeCalledWith({
sql: "UPDATE users SET full_name = :full_name, preferred_name = :preferred_name, sex = :sex, mobile_country_code = :mobile_country_code, mobile = :mobile, phone_number_verified = :phone_number_verified, id_number = :id_number, date_of_birth = :date_of_birth, nationality = :nationality, email = :email, addr_line_1 = :addr_line_1, addr_line_2 = :addr_line_2, addr_line_3 = :addr_line_3, addr_country = :addr_country, addr_postal = :addr_postal, created_at = :created_at, cka_status = :cka_status, ai_status = :ai_status, crs_status = :crs_status, verification_source = :verification_source, updated_at = DEFAULT WHERE id = :userId RETURNING *",
parameters: [
{ name: "full_name", value: "John Doe" },
{ name: "preferred_name", value: "John" },
{ name: "sex", value: "MALE", cast: "gender" },
{ name: "mobile_country_code", value: "94" },
{ name: "mobile", value: "778212132" },
{ name: "phone_number_verified", value: false },
{ name: "id_number", value: "93212312" },
{ name: "date_of_birth", value: "1990-10-05", cast: "date" },
{ name: "nationality", value: "Singaporean" },
{ name: "email", value: "john@gmail.com" },
{ name: "addr_line_1", value: "No 4" },
{ name: "addr_line_2", value: "Downing street" },
{ name: "addr_line_3", value: "Yemen" },
{ name: "addr_country", value: "Singapore" },
{ name: "addr_postal", value: "231" },
{ name: "created_at", value: "2022-08-01", cast: "timestamp" },
{ name: "cka_status", value: "NOT_TAKEN", cast: "ckaStatus" },
{ name: "ai_status", value: "NON_AI", cast: "aiStatus" },
{ name: "crs_status", value: "UNDECLARED", cast: "CRSStatus" },
{
name: "verification_source",
value: "SINGPASS",
cast: "verificationSource",
},
{ name: "userId", value: "123" },
],
});
});
it("should call deleteAllByIds", async () => {
const mockedDelete = jest.fn();
const mockedGet = jest.fn();
class MockIdentityProvider {
providerId: string;
adminDeleteUser(id: string) {
return Promise.resolve(mockedDelete(id));
}
adminGetUser(id: string) {
return Promise.resolve(mockedGet(id));
}
getUser(accessToken: string) {
return Promise.resolve(mockedGet(accessToken));
}
}
const userRepository = new UserRepository({
primaryIdProvider: new MockIdentityProvider(),
stepUpIdProvider: new MockIdentityProvider(),
client,
});
await userRepository.deleteAllByIds(["mockId1", "mockId2"]);
expect(client.query).toHaveBeenCalledWith({
sql: `DELETE FROM users WHERE id IN (:id0, :id1)`,
parameters: [
{ name: "id0", value: "mockId1" },
{ name: "id1", value: "mockId2" },
],
});
expect(mockedDelete).toHaveBeenNthCalledWith(1, "mockId1");
expect(mockedDelete).toHaveBeenNthCalledWith(2, "mockId2");
expect(mockedDelete).toHaveBeenNthCalledWith(3, "mockId1");
expect(mockedDelete).toHaveBeenNthCalledWith(4, "mockId2");
});
});