const path = require("path") const setupServer = require("../../../environment-helpers/setup-server") const { useApi } = require("../../../environment-helpers/use-api") const { initDb, useDb } = require("../../../environment-helpers/use-db") const adminSeeder = require("../../../helpers/admin-seeder") const { simpleProductFactory, simpleShippingOptionFactory, simpleRegionFactory, simpleTaxRateFactory, } = require("../../../factories") jest.setTimeout(30000) describe("/admin/tax-rates", () => { let medusaProcess let dbConnection const doAfterEach = async () => { const db = useDb() return await db.teardown() } beforeAll(async () => { const cwd = path.resolve(path.join(__dirname, "..", "..")) dbConnection = await initDb({ cwd }) medusaProcess = await setupServer({ cwd }) }) afterAll(async () => { const db = useDb() await db.shutdown() medusaProcess.kill() }) afterEach(async () => { return await doAfterEach() }) test("list tax rates", async () => { await adminSeeder(dbConnection) await createTaxRates(dbConnection, 20, 2, 200) const api = useApi() const response = await api.get("/admin/tax-rates", { headers: { "x-medusa-access-token": "test_token", }, }) expect(response.status).toEqual(200) expect(response.data.count).toEqual(20) }) test("list tax rates w. query", async () => { await adminSeeder(dbConnection) await createTaxRates(dbConnection, 20, 2, 200) const api = useApi() const response = await api.get( `/admin/tax-rates?fields[]=rate&fields[]=product_count&fields[]=id&expand[]=products&rate[gt]=80`, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rates.some((tr) => tr.rate <= 80)).toEqual(false) }) test("list tax rates w. region query", async () => { await adminSeeder(dbConnection) const { regions } = await createTaxRates(dbConnection, 20, 2, 200) const api = useApi() const response = await api.get( `/admin/tax-rates?region_id[]=${regions[0].id}®ion_id[]=${regions[1].id}`, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect( response.data.tax_rates.some( (tr) => tr.region_id !== regions[0].id && tr.region_id !== regions[1].id ) ).toEqual(false) }) test("get tax rates", async () => { await adminSeeder(dbConnection) const { tax_rates } = await createTaxRates(dbConnection, 20, 2, 200) const api = useApi() const response = await api.get(`/admin/tax-rates/${tax_rates[0].id}`, { headers: { "x-medusa-access-token": "test_token", }, }) expect(response.status).toEqual(200) expect(response.data.tax_rate).toMatchSnapshot({ id: expect.stringMatching(/^txr_*/), region_id: expect.any(String), created_at: expect.any(String), updated_at: expect.any(String), }) }) test("get tax rates w. fields", async () => { await adminSeeder(dbConnection) const { tax_rates } = await createTaxRates(dbConnection, 20, 2, 200) const api = useApi() const response = await api.get( `/admin/tax-rates/${tax_rates[0].id}?fields[]=id&fields[]=region_id`, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate).toMatchSnapshot({ id: expect.stringMatching(/^txr_*/), region_id: expect.any(String), }) }) test("assigns tax rate to product type", async () => { await adminSeeder(dbConnection) const { tax_rates } = await createTaxRates(dbConnection, 1, 1, 200) const [rate] = tax_rates const product = await simpleProductFactory(dbConnection, { type: "pants", }) const api = useApi() const response = await api.post( `/admin/tax-rates/${rate.id}/product-types/batch?fields[]=id&fields[]=region_id&fields[]=product_type_count&expand[]=product_types`, { product_types: [product.type_id], }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate.product_type_count).toEqual(1) expect(response.data.tax_rate.product_types[0].id).toEqual(product.type_id) }) test("assigns tax rate to multiple product type", async () => { await adminSeeder(dbConnection) const { tax_rates } = await createTaxRates(dbConnection, 1, 1, 200) const [rate] = tax_rates const products = await Promise.all( [0, 1, 2, 3].map((i) => simpleProductFactory(dbConnection, { type: `pants-${i}`, }) ) ) const api = useApi() const response = await api.post( `/admin/tax-rates/${rate.id}/product-types/batch?fields[]=id&fields[]=region_id&fields[]=product_type_count&expand[]=product_types`, { product_types: products.map((product) => product.type_id), }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate.product_type_count).toEqual(4) expect(response.data.tax_rate.product_types[0].id).toEqual( products[0].type_id ) expect(response.data.tax_rate.product_types[1].id).toEqual( products[1].type_id ) expect(response.data.tax_rate.product_types[2].id).toEqual( products[2].type_id ) expect(response.data.tax_rate.product_types[3].id).toEqual( products[3].type_id ) }) test("fails with 404 on unknown rate", async () => { await adminSeeder(dbConnection) const { tax_rates } = await createTaxRates(dbConnection, 1, 1, 200) const [rate] = tax_rates await Promise.all( [0, 1, 2, 3].map(() => simpleProductFactory(dbConnection)) ) const api = useApi() const response = await api .post( `/admin/tax-rates/${rate.id}/products/batch?fields[]=id&fields[]=product_count&expand[]=products`, { products: ["unknown_product_id"], }, { headers: { "x-medusa-access-token": "test_token", }, } ) .catch((err) => err.response) expect(response.status).toEqual(404) expect(response.data.message).toEqual( "Product with id: unknown_product_id was not found" ) }) test("fails with 404 on unknown prod", async () => { await adminSeeder(dbConnection) await createTaxRates(dbConnection, 1, 1, 200) const products = await Promise.all( [0, 1, 2, 3].map(() => simpleProductFactory(dbConnection)) ) const api = useApi() const response = await api .post( `/admin/tax-rates/unknown_rate/products/batch?fields[]=id&fields[]=product_count&expand[]=products`, { products: products.map((product) => product.id), }, { headers: { "x-medusa-access-token": "test_token", }, } ) .catch((err) => err.response) expect(response.status).toEqual(404) expect(response.data.message).toEqual( "TaxRate with unknown_rate was not found" ) }) test("fails to assign rate to shipping option with different reg", async () => { await adminSeeder(dbConnection) const { tax_rates, regions } = await createTaxRates(dbConnection, 1, 1, 200) const [reg] = regions const [rate] = tax_rates const difReg = await simpleRegionFactory(dbConnection) const option = await simpleShippingOptionFactory(dbConnection, { name: "Test option", region_id: difReg, }) const api = useApi() const response = await api .post( `/admin/tax-rates/${rate.id}/shipping-options/batch?fields[]=id&fields[]=shipping_option_count&expand[]=shipping_options`, { shipping_options: [option.id], }, { headers: { "x-medusa-access-token": "test_token", }, } ) .catch((err) => err.response) expect(response.status).toEqual(400) expect(response.data.message).toEqual( `Shipping Option and Tax Rate must belong to the same Region to be associated. Shipping Option with id: ${option.id} belongs to Region with id: ${option.region_id} and Tax Rate with id: ${rate.id} belongs to Region with id: ${rate.region_id}` ) }) test("assigns tax rate to shipping option", async () => { await adminSeeder(dbConnection) const { tax_rates, regions } = await createTaxRates(dbConnection, 1, 1, 200) const [reg] = regions const [rate] = tax_rates const options = await Promise.all( [0, 1, 2, 3].map((i) => simpleShippingOptionFactory(dbConnection, { name: i, region_id: reg.id, }) ) ) const api = useApi() const response = await api.post( `/admin/tax-rates/${rate.id}/shipping-options/batch?fields[]=id&fields[]=shipping_option_count&expand[]=shipping_options`, { shipping_options: options.map((o) => o.id), }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate.shipping_option_count).toEqual(4) expect(response.data.tax_rate.shipping_options[0].id).toEqual(options[0].id) expect(response.data.tax_rate.shipping_options[1].id).toEqual(options[1].id) expect(response.data.tax_rate.shipping_options[2].id).toEqual(options[2].id) expect(response.data.tax_rate.shipping_options[3].id).toEqual(options[3].id) }) test("assigns tax rate to products", async () => { await adminSeeder(dbConnection) const { tax_rates } = await createTaxRates(dbConnection, 1, 1, 200) const [rate] = tax_rates const products = await Promise.all( [0, 1, 2, 3].map(() => simpleProductFactory(dbConnection)) ) const api = useApi() const response = await api.post( `/admin/tax-rates/${rate.id}/products/batch?fields[]=id&fields[]=product_count&expand[]=products`, { products: products.map((product) => product.id), }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate.product_count).toEqual(4) expect(response.data.tax_rate.products[0].id).toEqual(products[0].id) expect(response.data.tax_rate.products[1].id).toEqual(products[1].id) expect(response.data.tax_rate.products[2].id).toEqual(products[2].id) expect(response.data.tax_rate.products[3].id).toEqual(products[3].id) }) test("creates a tax rate", async () => { await adminSeeder(dbConnection) const api = useApi() await simpleRegionFactory(dbConnection, { id: "test-region", }) const response = await api.post( `/admin/tax-rates`, { name: "special", code: "tricks", region_id: "test-region", }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate).toEqual( expect.objectContaining({ id: expect.stringMatching(/^txr_*/), name: "special", code: "tricks", rate: null, }) ) }) test("creates a tax rate with a rate", async () => { await adminSeeder(dbConnection) const api = useApi() await simpleRegionFactory(dbConnection, { id: "test-region", }) const response = await api.post( `/admin/tax-rates`, { name: "special", code: "tricks", region_id: "test-region", rate: 2, }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate).toEqual( expect.objectContaining({ id: expect.stringMatching(/^txr_*/), name: "special", code: "tricks", region_id: "test-region", rate: 2, }) ) }) test("creates a tax rate with a null rate", async () => { await adminSeeder(dbConnection) const api = useApi() await simpleRegionFactory(dbConnection, { id: "test-region", }) const response = await api.post( `/admin/tax-rates`, { name: "special", code: "tricks", region_id: "test-region", rate: null, }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate).toEqual( expect.objectContaining({ id: expect.stringMatching(/^txr_*/), name: "special", code: "tricks", region_id: "test-region", rate: null, }) ) }) test("creates a tax rate and assigns products", async () => { await adminSeeder(dbConnection) const products = await Promise.all( [0, 1, 2, 3].map(() => simpleProductFactory(dbConnection)) ) await simpleRegionFactory(dbConnection, { id: "test-region", }) const api = useApi() const response = await api.post( `/admin/tax-rates?fields[]=product_count&expand[]=products`, { name: "special", code: "tricks", region_id: "test-region", products: products.map((p) => p.id), }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate.product_count).toEqual(4) }) test("updates a tax rate", async () => { await adminSeeder(dbConnection) await simpleRegionFactory(dbConnection, { id: "test-region" }) const rate = await simpleTaxRateFactory(dbConnection, { name: "test", code: "something", rate: 10, region_id: "test-region", }) const api = useApi() const response = await api.post( `/admin/tax-rates/${rate.id}`, { name: "special", code: "something new", rate: 5, }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate).toEqual( expect.objectContaining({ id: expect.stringMatching(/^txr_*/), name: "special", code: "something new", rate: 5, }) ) }) test("updates a tax rate with null rate", async () => { await adminSeeder(dbConnection) await simpleRegionFactory(dbConnection, { id: "test-region" }) const rate = await simpleTaxRateFactory(dbConnection, { name: "test", code: "something", rate: 10, region_id: "test-region", }) const api = useApi() const response = await api.post( `/admin/tax-rates/${rate.id}`, { rate: null, }, { headers: { "x-medusa-access-token": "test_token", }, } ) expect(response.status).toEqual(200) expect(response.data.tax_rate).toEqual( expect.objectContaining({ id: expect.stringMatching(/^txr_*/), rate: null, }) ) }) test("deletes a tax rate", async () => { await adminSeeder(dbConnection) await simpleRegionFactory(dbConnection, { id: "test-region" }) const rate = await simpleTaxRateFactory(dbConnection, { name: "test", code: "something", rate: 10, region_id: "test-region", }) const api = useApi() const response = await api.delete(`/admin/tax-rates/${rate.id}`, { headers: { "x-medusa-access-token": "test_token", }, }) expect(response.status).toEqual(200) expect(response.data).toMatchSnapshot({ id: expect.stringMatching(/^txr_*/), }) }) }) const createTaxRates = async (dbConnection, num, numRegions, seed) => { const regions = [] for (let i = 0; i < numRegions; i++) { const reg = await simpleRegionFactory(dbConnection, {}, seed + i) regions.push(reg) } const tax_rates = [] for (let x = 0; x < num; x++) { const { id } = regions[Math.floor(Math.random() * regions.length)] const rate = await simpleTaxRateFactory( dbConnection, { region_id: id, }, seed + x ) tax_rates.push(rate) } return { regions, tax_rates } }