diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 46e33a47..8b39fad2 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -60,7 +60,7 @@ jobs: env: GRAPHQL_API_URL: https://api.kwekmarket.com/v1/kwekql PORT: 3100 - run: yarn playwright test + run: yarn run test - uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} diff --git a/package.json b/package.json index c5a98dca..8c3437ca 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,13 @@ "build": "NODE_OPTIONS=--max-old-space-size=4096 next build", "start": "NODE_ENV=production next start", "lint": "next lint", - "check-lint": "eslint ." + "check-lint": "eslint .", + "test": "playwright test", + "test:debug": "playwright test --debug", + "test:headed": "playwright test --headed", + "test:filter": "playwright test --grep @tag", + "test:update": "playwright test --update-snapshots", + "test:report": "playwright show-report" }, "dependencies": { "@ckeditor/ckeditor5-react": "^9.0.0", @@ -57,6 +63,7 @@ "redux-logger": "^3.0.6", "redux-thunk": "^3.1.0", "sass": "^1.77.8", + "sharp": "^0.33.5", "tailwind-merge": "^2.5.4", "tailwind-scrollbar": "^3.1.0", "use-debounce": "^10.0.1", diff --git a/playwright.config.ts b/playwright.config.ts index f8dc0989..24d3a351 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,38 +1,40 @@ import { defineConfig, devices } from '@playwright/test'; - -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// import dotenv from 'dotenv'; -// import path from 'path'; -// dotenv.config({ path: path.resolve(__dirname, '.env') }); - -/** - * See https://playwright.dev/docs/test-configuration. - */ export default defineConfig({ + timeout: 60000, // Set global timeout to 60 seconds + testDir: './tests', + + /* Run tests in files in parallel */ fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [['html', { open: 'on-failure' }]], + + + reporter: [['html', { open: 'always' }]], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { /* Base URL to use in actions like `await page.goto('/')`. */ - baseURL: 'http://localhost:3100', + + baseURL: 'http://localhost:3100', + headless: true, // Run tests in headed mode + // Other options... /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + trace: 'on-first-retry', /* Capture a screenshot for failed tests */ - screenshot: 'only-on-failure', + screenshot: 'only-on-failure', }, /* Configure projects for major browsers */ @@ -42,41 +44,26 @@ export default defineConfig({ use: { ...devices['Desktop Chrome'] }, }, - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, + // { + // name: 'firefox', + // use: { ...devices['Desktop Firefox'] }, + // }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, /* Test against mobile viewports. */ - { - name: 'Mobile Chrome', - use: { ...devices['Pixel 5'] }, - }, - { - name: 'Mobile Safari', - use: { ...devices['iPhone 12'] }, - }, - - /* Test against branded browsers. */ // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, // }, // { - // name: 'Google Chrome', - // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, // }, + ], - /* Run your local dev server before starting the tests */ - // webServer: { - // command: 'npm run start', - // url: 'http://127.0.0.1:3000', - // reuseExistingServer: !process.env.CI, - // }, }); \ No newline at end of file diff --git a/tests/auths/createAccount.spec.ts b/tests/auth/createAccount.spec.ts similarity index 98% rename from tests/auths/createAccount.spec.ts rename to tests/auth/createAccount.spec.ts index 0942b46c..d760f640 100644 --- a/tests/auths/createAccount.spec.ts +++ b/tests/auth/createAccount.spec.ts @@ -1,5 +1,4 @@ import { test, expect } from '@playwright/test'; -import { AuthHelpers } from '../utils/helpers'; function generateRandomEmail() { const timestamp = Date.now(); diff --git a/tests/auths/login.spec.ts b/tests/auth/login.spec.ts similarity index 100% rename from tests/auths/login.spec.ts rename to tests/auth/login.spec.ts diff --git a/tests/dashboard/categories.spec.ts b/tests/dashboard/categories.spec.ts new file mode 100644 index 00000000..fe0b7537 --- /dev/null +++ b/tests/dashboard/categories.spec.ts @@ -0,0 +1,50 @@ +import { test, expect, Page } from '@playwright/test'; + +test.describe('Categories Tests', () => { + const baseURL = 'http://localhost:3100'; + let page: Page; + + test.beforeAll(async ({ browser }) => { + const context = await browser.newContext(); + page = await context.newPage(); + await page.goto(baseURL, { waitUntil: 'domcontentloaded' }); + }); + + test.skip ('Validate categories section', async () => { + const categories = [ + 'Vehicles & Equipment', + 'Beauty & Personal care', + 'Home & Garden', + 'Baby & Toddler Toys', + 'Fashion', + ]; + + const categoryMenu = page.locator('div:has-text("All Categories")'); + await expect(categoryMenu).toBeVisible(); + + for (const category of categories) { + const categoryLocator = page.locator(`text=${category}`); + await expect(categoryLocator).toBeVisible(); + await categoryLocator.hover(); + } + }); + + test('Verify promotional banner for Women section', async () => { + const promoText = 'BUY TWO, Get FOR WOMEN Get up to 30% Off'; + const promoBanner = page.locator(`text=${promoText}`).first(); + const shopNowButton = page.locator('text=SHOP NOW'); + + if (await promoBanner.count() > 0) { + await expect(promoBanner).toBeVisible(); + await expect(shopNowButton).toBeVisible(); + await shopNowButton.click(); + await expect(page).toHaveURL(/.*shop/);} + // } else { + // console.warn('Promotional banner not found. Skipping test.'); + // } + }); + + test.afterAll(async () => { + await page.close(); + }); +}); diff --git a/tests/dashboard/nav.spec.ts b/tests/dashboard/nav.spec.ts new file mode 100644 index 00000000..f7b2f495 --- /dev/null +++ b/tests/dashboard/nav.spec.ts @@ -0,0 +1,86 @@ +import { test, expect } from "@playwright/test"; + +test.describe("Header Tests", () => { + test.beforeEach(async ({ page }) => { + // Navigate to the homepage + await page.goto("http://localhost:3100"); + }); + + test.skip("Logo should navigate to the homepage", async ({ page }) => { + // Click on the logo + await page.locator('img[alt="Kwek Market"]').click(); + + // Assert the page URL is the homepage + await expect(page).toHaveURL("http://localhost:3100"); + }); + + + + test.skip("Search bar should allow input and search", async ({ page }) => { + const searchBar = page.locator('input[placeholder="I\'m searching for..."]'); + const searchButton = page.locator('button:has-text("Search")'); + + // Type into the search bar + await searchBar.fill("Test Query"); + + // Click the search button + await searchButton.click({ timeout: 30000 }); + + // Wait for navigation to complete + await page.waitForNavigation({ timeout: 30000 }); + + // Assert the URL contains the search query + await expect(page).toHaveURL(/.*search.*/); // Update the regex based on your site's search functionality + + // Assert that no results are found + const noResultsMessage = page.locator('text=No items found'); // Update the selector based on your site's implementation + await expect(noResultsMessage).toBeVisible({ timeout: 30000 }); + }); + + + +test("Wishlist icon should navigate to wishlist page", async ({ page }) => { + // Find the element with the text 'saved' and click on it + const savedLink = page.locator('text=saved'); + await savedLink.waitFor({ state: 'visible', timeout: 30000 }); // Ensure the element is visible + await savedLink.click({ timeout: 30000 }); + + // Assert the page URL is the wishlist page + await expect(page).toHaveURL("http://localhost:3100/wishlist"); + + // Pause the test to keep the browser open +// await page.pause(); +}); + + test("Cart icon should navigate to cart page", async ({ page }) => { + // Click on the cart icon + const cartLink = page.locator('text=cart'); + await cartLink.waitFor({ state: 'visible', timeout: 30000 }); // Ensure the element is visible + await cartLink.click({ timeout: 30000 }); + + // Assert the page URL is the cart page + await expect(page).toHaveURL("http://localhost:3100/cart"); + + // Pause the test to keep the browser open + await page.pause(); + }); + + test("Shortcut items should have correct counters", async ({ page }) => { + // Check the wishlist counter + const wishlistCounter = page.locator('a[href="/wishlist"] .tw-absolute'); + await expect(wishlistCounter).toHaveText("0"); + + // Check the cart counter + const cartCounter = page.locator('a[href="/cart"] .tw-absolute'); + await expect(cartCounter).toHaveText("0"); + }); + + test("Sign In link should navigate to login page", async ({ page }) => { + // Click on the Sign In link + const signInLink = page.locator('a[href="/login"]'); + await signInLink.click(); + + // Assert the page URL is the login page + await expect(page).toHaveURL("http://localhost:3100/login"); + }); +}); diff --git a/tests/dashboard/socials.spec.ts b/tests/dashboard/socials.spec.ts new file mode 100644 index 00000000..c5b3c20a --- /dev/null +++ b/tests/dashboard/socials.spec.ts @@ -0,0 +1,34 @@ +import { test, expect, Page } from '@playwright/test'; + +test.describe('Social Media Tests', () => { + const baseURL = 'http://localhost:3100'; + let page: Page; + + test.beforeAll(async ({ browser }) => { + const context = await browser.newContext(); + page = await context.newPage(); + await page.goto(baseURL, { waitUntil: 'domcontentloaded' }); + }); + + test.skip('Hover on social media links', async () => { + const socialLinks = ['Facebook', 'Instagram', 'Twitter']; + + const socialSection = page.locator('.Footer_social__mdVIK'); + for (const social of socialLinks) { + const socialLink = socialSection.locator(`text=${social}`); + await expect(socialLink).toBeVisible(); + await socialLink.hover(); + } + }); + + test('Hover on missing social media links', async () => { + const socialSection = page.locator('.Footer_social__mdVIK'); + const missingLink = socialSection.locator('text=Snapchat'); + + await expect(missingLink).toHaveCount(0); + }); + + test.afterAll(async () => { + await page.close(); + }); +}); diff --git a/tests/dashboard/subscription.spec.ts b/tests/dashboard/subscription.spec.ts new file mode 100644 index 00000000..05f31e8a --- /dev/null +++ b/tests/dashboard/subscription.spec.ts @@ -0,0 +1,46 @@ +import { test, expect, Page } from '@playwright/test'; + +test.describe.skip('Subscription Tests', () => { + const baseURL = 'http://localhost:3100'; + let page: Page; + + test.beforeAll(async ({ browser }) => { + const context = await browser.newContext(); + page = await context.newPage(); + await page.goto(baseURL, { waitUntil: 'domcontentloaded' }); + }); + + test('Email subscription with valid email', async () => { + const emailInput = page.locator('input[placeholder="Enter your email address..."]'); + const subscribeButton = page.locator('button:has-text("Subscribe")'); + + await emailInput.fill('valid@example.com'); + await subscribeButton.click(); + + const successMessage = page.locator('text=Subscription Successful'); + await expect(successMessage).toBeVisible(); + }); + + test('Email subscription with empty input', async () => { + const subscribeButton = page.locator('button:has-text("Subscribe")'); + await subscribeButton.click(); + + const errorMessage = page.locator('text=Please enter a valid email address'); + await expect(errorMessage).toBeVisible(); + }); + + test('Email subscription with invalid format', async () => { + const emailInput = page.locator('input[placeholder="Enter your email address..."]'); + const subscribeButton = page.locator('button:has-text("Subscribe")'); + + await emailInput.fill('invalid-email'); + await subscribeButton.click(); + + const errorMessage = page.locator('text=Please enter a valid email address'); + await expect(errorMessage).toBeVisible(); + }); + + test.afterAll(async () => { + await page.close(); + }); +}); diff --git a/tests/test.ts b/tests/test.ts deleted file mode 100644 index 8b137891..00000000 --- a/tests/test.ts +++ /dev/null @@ -1 +0,0 @@ - diff --git a/yarn.lock b/yarn.lock index ce610f80..b4941aea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -845,6 +845,15 @@ __metadata: languageName: node linkType: hard +"@emnapi/runtime@npm:^1.2.0": + version: 1.3.1 + resolution: "@emnapi/runtime@npm:1.3.1" + dependencies: + tslib: ^2.4.0 + checksum: 9a16ae7905a9c0e8956cf1854ef74e5087fbf36739abdba7aa6b308485aafdc993da07c19d7af104cd5f8e425121120852851bb3a0f78e2160e420a36d47f42f + languageName: node + linkType: hard + "@emotion/hash@npm:^0.8.0": version: 0.8.0 resolution: "@emotion/hash@npm:0.8.0" @@ -1050,6 +1059,181 @@ __metadata: languageName: node linkType: hard +"@img/sharp-darwin-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-arm64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-darwin-arm64": + optional: true + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-darwin-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-darwin-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-darwin-x64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-darwin-x64": + optional: true + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@img/sharp-libvips-darwin-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-arm@npm:1.0.5": + version: 1.0.5 + resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-s390x@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linux-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-libvips-linuxmusl-x64@npm:1.0.4": + version: 1.0.4 + resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linux-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linux-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-arm@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-arm@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-arm": 1.0.5 + dependenciesMeta: + "@img/sharp-libvips-linux-arm": + optional: true + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-s390x@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-s390x@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-s390x": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linux-s390x": + optional: true + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linux-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linux-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linux-x64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linux-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-arm64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-linuxmusl-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5" + dependencies: + "@img/sharp-libvips-linuxmusl-x64": 1.0.4 + dependenciesMeta: + "@img/sharp-libvips-linuxmusl-x64": + optional: true + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@img/sharp-wasm32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-wasm32@npm:0.33.5" + dependencies: + "@emnapi/runtime": ^1.2.0 + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@img/sharp-win32-ia32@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-ia32@npm:0.33.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@img/sharp-win32-x64@npm:0.33.5": + version: 0.33.5 + resolution: "@img/sharp-win32-x64@npm:0.33.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -2706,6 +2890,26 @@ __metadata: languageName: node linkType: hard +"color-string@npm:^1.9.0": + version: 1.9.1 + resolution: "color-string@npm:1.9.1" + dependencies: + color-name: ^1.0.0 + simple-swizzle: ^0.2.2 + checksum: c13fe7cff7885f603f49105827d621ce87f4571d78ba28ef4a3f1a104304748f620615e6bf065ecd2145d0d9dad83a3553f52bb25ede7239d18e9f81622f1cc5 + languageName: node + linkType: hard + +"color@npm:^4.2.3": + version: 4.2.3 + resolution: "color@npm:4.2.3" + dependencies: + color-convert: ^2.0.1 + color-string: ^1.9.0 + checksum: 0579629c02c631b426780038da929cca8e8d80a40158b09811a0112a107c62e10e4aad719843b791b1e658ab4e800558f2e87ca4522c8b32349d497ecb6adeb4 + languageName: node + linkType: hard + "combined-stream@npm:^1.0.8": version: 1.0.8 resolution: "combined-stream@npm:1.0.8" @@ -2969,6 +3173,13 @@ __metadata: languageName: node linkType: hard +"detect-libc@npm:^2.0.3": + version: 2.0.3 + resolution: "detect-libc@npm:2.0.3" + checksum: 2ba6a939ae55f189aea996ac67afceb650413c7a34726ee92c40fb0deb2400d57ef94631a8a3f052055eea7efb0f99a9b5e6ce923415daa3e68221f963cfc27d + languageName: node + linkType: hard + "detect-node@npm:^2.0.4, detect-node@npm:^2.1.0": version: 2.1.0 resolution: "detect-node@npm:2.1.0" @@ -4226,6 +4437,13 @@ __metadata: languageName: node linkType: hard +"is-arrayish@npm:^0.3.1": + version: 0.3.2 + resolution: "is-arrayish@npm:0.3.2" + checksum: 977e64f54d91c8f169b59afcd80ff19227e9f5c791fa28fa2e5bce355cbaf6c2c356711b734656e80c9dd4a854dd7efcf7894402f1031dfc5de5d620775b4d5f + languageName: node + linkType: hard + "is-async-function@npm:^2.0.0": version: 2.0.0 resolution: "is-async-function@npm:2.0.0" @@ -4758,6 +4976,7 @@ __metadata: redux-logger: ^3.0.6 redux-thunk: ^3.1.0 sass: ^1.77.8 + sharp: ^0.33.5 tailwind-merge: ^2.5.4 tailwind-scrollbar: ^3.1.0 tailwindcss: ^3.4.6 @@ -6914,7 +7133,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.5, semver@npm:^7.5.4, semver@npm:^7.6.0": +"semver@npm:^7.3.5, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3": version: 7.6.3 resolution: "semver@npm:7.6.3" bin: @@ -6963,6 +7182,75 @@ __metadata: languageName: node linkType: hard +"sharp@npm:^0.33.5": + version: 0.33.5 + resolution: "sharp@npm:0.33.5" + dependencies: + "@img/sharp-darwin-arm64": 0.33.5 + "@img/sharp-darwin-x64": 0.33.5 + "@img/sharp-libvips-darwin-arm64": 1.0.4 + "@img/sharp-libvips-darwin-x64": 1.0.4 + "@img/sharp-libvips-linux-arm": 1.0.5 + "@img/sharp-libvips-linux-arm64": 1.0.4 + "@img/sharp-libvips-linux-s390x": 1.0.4 + "@img/sharp-libvips-linux-x64": 1.0.4 + "@img/sharp-libvips-linuxmusl-arm64": 1.0.4 + "@img/sharp-libvips-linuxmusl-x64": 1.0.4 + "@img/sharp-linux-arm": 0.33.5 + "@img/sharp-linux-arm64": 0.33.5 + "@img/sharp-linux-s390x": 0.33.5 + "@img/sharp-linux-x64": 0.33.5 + "@img/sharp-linuxmusl-arm64": 0.33.5 + "@img/sharp-linuxmusl-x64": 0.33.5 + "@img/sharp-wasm32": 0.33.5 + "@img/sharp-win32-ia32": 0.33.5 + "@img/sharp-win32-x64": 0.33.5 + color: ^4.2.3 + detect-libc: ^2.0.3 + semver: ^7.6.3 + dependenciesMeta: + "@img/sharp-darwin-arm64": + optional: true + "@img/sharp-darwin-x64": + optional: true + "@img/sharp-libvips-darwin-arm64": + optional: true + "@img/sharp-libvips-darwin-x64": + optional: true + "@img/sharp-libvips-linux-arm": + optional: true + "@img/sharp-libvips-linux-arm64": + optional: true + "@img/sharp-libvips-linux-s390x": + optional: true + "@img/sharp-libvips-linux-x64": + optional: true + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + "@img/sharp-libvips-linuxmusl-x64": + optional: true + "@img/sharp-linux-arm": + optional: true + "@img/sharp-linux-arm64": + optional: true + "@img/sharp-linux-s390x": + optional: true + "@img/sharp-linux-x64": + optional: true + "@img/sharp-linuxmusl-arm64": + optional: true + "@img/sharp-linuxmusl-x64": + optional: true + "@img/sharp-wasm32": + optional: true + "@img/sharp-win32-ia32": + optional: true + "@img/sharp-win32-x64": + optional: true + checksum: 04beae89910ac65c5f145f88de162e8466bec67705f497ace128de849c24d168993e016f33a343a1f3c30b25d2a90c3e62b017a9a0d25452371556f6cd2471e4 + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -6998,6 +7286,15 @@ __metadata: languageName: node linkType: hard +"simple-swizzle@npm:^0.2.2": + version: 0.2.2 + resolution: "simple-swizzle@npm:0.2.2" + dependencies: + is-arrayish: ^0.3.1 + checksum: a7f3f2ab5c76c4472d5c578df892e857323e452d9f392e1b5cf74b74db66e6294a1e1b8b390b519fa1b96b5b613f2a37db6cffef52c3f1f8f3c5ea64eb2d54c0 + languageName: node + linkType: hard + "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0"