Skip to content

Importing a file which uses "$app/environment": Cannot read properties of undefined (reading 'SSR') #2298

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
6 tasks done
silverbucket opened this issue Nov 8, 2022 · 10 comments · Fixed by sveltejs/kit#7950
Labels

Comments

@silverbucket
Copy link

silverbucket commented Nov 8, 2022

Describe the bug

I'm trying to get started writing unit tests for my Svelte/SvelteKit app using vitest. However a few files use some variables from the "$app/environment" which causes an exception to be thrown in vitest:

TypeError: Cannot read properties of undefined (reading 'SSR')
 ❯ node_modules/@sveltejs/kit/src/runtime/app/environment.js:4:41
      2|  * @type {import('$app/environment').browser}
      3|  */
      4| export const browser = !import.meta.env.SSR;
       |                                         ^
      5|
      6| /**
 ❯ ModuleJob.run node:internal/modules/esm/module_job:193:25
 ❯ ESMLoader.import node:internal/modules/esm/loader:530:24
 ❯ VitestRunner.interopedImport node_modules/vitest/dist/chunk-vite-node-client.13ea0a59.js:285:17
 ❯ VitestRunner.directRequest node_modules/vitest/dist/chunk-vite-node-client.13ea0a59.js:191:24
 ❯ VitestRunner.cachedRequest node_modules/vitest/dist/chunk-vite-node-client.13ea0a59.js:144:12
 ❯ _VitestMocker.request node_modules/vitest/dist/chunk-vite-node-client.13ea0a59.js:167:16
 ❯ src/lib/auth.ts:5:31
 ❯ VitestRunner.directRequest node_modules/vitest/dist/chunk-vite-node-client.13ea0a59.js:268:5

Reproduction

Create a Svelte .ts file, which imports, for example, the browser or dev constant:

import { browser } from "$app/environment";
export const testValue = true;

Create a vitest spec file which imports this file:

import { assert, describe, expect, it, vi } from "vitest";
import {testValue} from "./env";

describe("request lib", () => {
  it("should be true", () => {
    expect(testValue).to.eql(true);
  })
})

I've also tried to vi.importMock the "$app/environment" with no luck:

import { assert, describe, expect, it, vi } from "vitest";
import {testValue} from "./env";

vi.importMock("$app/environment");

describe("request lib", () => {
  it("should be true", () => {
    expect(testValue).to.eql(true);
  })
})

My vitest.config.ts file looks like this:

import viteConfig from './vite.config'
import {defineConfig} from 'vitest/config'
import {mergeConfig} from "vite";

export default mergeConfig(viteConfig, defineConfig({
  test: {
    include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
    globals: true,
    environment: 'jsdom',
  },
}))

And my vite.config.ts:

import { sveltekit } from '@sveltejs/kit/vite';
import type { UserConfig } from 'vite';

const config: UserConfig = {
	plugins: [sveltekit()],
	server: {
		port: 59000,
		fs: {
			allow: ['.']
		}
	}
};

export default config;

System Info

System:
    OS: macOS 12.6.1
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    Memory: 761.88 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.11.0 - ~/.nvm/versions/node/v18.11.0/bin/node
    Yarn: 3.2.4 - ~/.nvm/versions/node/v18.11.0/bin/yarn
    npm: 8.19.2 - ~/.nvm/versions/node/v18.11.0/bin/npm
  Browsers:
    Brave Browser: 107.1.45.116
    Chrome: 107.0.5304.87
    Firefox: 103.0.2
    Safari: 16.1
  npmPackages:
    vite: ^3.1.0 => 3.1.8
    vitest: ^0.25.0 => 0.25.0

Used Package Manager

yarn

Validations

@sheremet-va
Copy link
Member

As you can see by this line in stacktrace:

 ❯ ModuleJob.run node:internal/modules/esm/module_job:193:25

Importing svelte module was delegated to Node. You can fix it by including /@svelte/ in your deps.inline options.

But I thought Svelte team is using ssr.external to inline its modules, @dominikg? Were there any changes to that? Vitest inlines these modules by default.

@dominikg
Copy link
Contributor

dominikg commented Nov 8, 2022

no changes that i'm aware of. sveltekit and vite-plugin-svelte auto-generate vite config, is that retained in vitest? ie does it honor the config returned after all config hooks of plugins are done?

Would need a reproduction project and i'd recommend checking with pnpm (to rule out yarn pnp issues) and also without a merged config in vitest.config.ts, instead just add the test key to vite.config.js generated from pnpm create svelte@latest

@dominikg
Copy link
Contributor

dominikg commented Nov 8, 2022

maybe @nickbreaton has an idea about aliases support.

@sheremet-va
Copy link
Member

sheremet-va commented Nov 8, 2022

I think alias is working, since it tries to load file inside node_modules. But I don’t understand why it’s not processed by Vitest 🤔

Isn’t this package inlined with ssr.external?

Now that I wrote this, I think the problem might be with how we check the package 🫣 It’s a simple „node_modules/${name}“ check - this is probably why it doesn’t work with externals and yarn.

@dominikg
Copy link
Contributor

dominikg commented Nov 8, 2022

vite-plugin-svelte-kit indeed sets ssr.external for @sveltejs/kit https://github.com/sveltejs/kit/blob/master/packages/kit/src/exports/vite/index.js#L279

resolved ssr config

{
  format: 'esm',
  target: 'node',
  noExternal: [ 'svelte', /^svelte\//, '@testing-library/svelte' ],
  external: [ '@testing-library/dom', '@sveltejs/kit' ],
  optimizeDeps: { disabled: true, esbuildOptions: { preserveSymlinks: false } }
}

using $app/environment import in a component under test causes the above error, using import.meta.env.SSR directly doesn't 🤔

adding deps: {inline:["@sveltejs/kit"] in vitest test config fixes the error with the import.

The value for import.meta.env.SSR is 1, which i guess can be expected when vitest uses ssr features, but depending on the feature you want to test, you may need it to be 0. How would that work?

@sheremet-va
Copy link
Member

using $app/environment import in a component under test causes the above error, using import.meta.env.SSR directly doesn't 🤔

Vitest delegates importing files from @sveltejs/kit to Node, and Node doesn't know what import.meta.env.SSR is. How does it work internally in Vite SSR?

The value for import.meta.env.SSR is 1, which i guess can be expected when vitest uses ssr features, but depending on the feature you want to test, you may need it to be 0. How would that work?

You can define env to override it:

SSR="" vitest

Or in config:

export default {
  test: {
    env: {
      SSR: ''
    }
  }
}

You can also just reassign it:

import.meta.env.SSR = ''

All import.meta.env are transformed to process.env, so they can be reassigned in runtime, this is why they have to be falsy/truthy strings.

@dominikg
Copy link
Contributor

dominikg commented Nov 8, 2022

related: vitejs/vite#8952

should kit be in noExternal then for vitest?

@dominikg
Copy link
Contributor

dominikg commented Nov 9, 2022

also related/same problem: sveltejs/kit#6259

@sheremet-va
Copy link
Member

should kit be in noExternal then for vitest?

Vitest runs code through Vite-compatible runtime only in this situations:

  • The file is not in node_modules
  • The file is in deps.inline
  • The file is in ssr.noExternal

If it's not in one of those, code will just me imported using Node native import function.

@benmccann
Copy link
Contributor

This should be fixed as of @sveltejs/[email protected] which removes the use of import.meta.env.SSR. Please try again and test the new version

@github-actions github-actions bot locked and limited conversation to collaborators Jun 8, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants