modernweb-dev / web

Guides, tools and libraries for modern web development.
https://modern-web.dev
MIT License
2.23k stars 297 forks source link

[web-test-runner] lit-element, scss and webpack. #1281

Open msteller-connyun opened 3 years ago

msteller-connyun commented 3 years ago

Hey,

I have some web components done with lit-element and want use web-test-runner for unit-testing. As build system I’m using webpack and importing the scss via the lit-scss-loader ( https://www.npmjs.com/package/lit-scss-loader ).

In an ideal world, I could just use my webpack build for doing the unit tests via web-test-runner, but there seems no way to do so.

Currently I’m trying to get esbuild for web-test-runner as close as possible to my webpack config. Everything seems to work fine, expect for scss. I tried to use some rollup scss plugins, without success.

I found a configuration, where at least the tests running:

import { playwrightLauncher } from '@web/test-runner-playwright';
import { esbuildPlugin } from '@web/dev-server-esbuild';

export default {
    nodeResolve: true,
    manual: true,
    open: true,
    plugins: [esbuildPlugin({ ts: true, target: 'es2020', loaders: { '.scss': 'text' }  })],
    browsers: [
        playwrightLauncher({
            launchOptions: {
                headless: false,
                devtools: true,
                slowMo: 10000
            },
        }),
    ],
};

With this configuration, my scss files are handles as text. That means I get the tests starting, but having in my browser scss code, instead of css.

web-test-runner seems to lack the option to transpile scss.

Is there a way to get scss working with web-test-runner or using my webpack build result?

LarsDenBakker commented 3 years ago

Web test runner only implements running tests, if your code needs a build step this you need to run this before the code is served to the browser. There is a plugin API to do this, and we have an easy way to interface with esbuild and rollup to reuse their loader/plugin system.

So in your case you would either need to look into an esbuild loader for SCSS, or a rollup plugin that does the same. We have some guides on using or writing plugins here: https://modern-web.dev/guides/dev-server/using-plugins/

Alternatively if you rely fully on webpack, you can run that in watch mode and run tests on the build output.

msteller-connyun commented 3 years ago

@LarsDenBakker Using parcel plugins for scss was the first thing I tried, but they didn’t seem to work.

However, I also tested the esbuild plugin for SCSS, which looks very promising, after it has lit support: https://www.npmjs.com/package/esbuild-sass-plugin

But esbuildPlugin from @web/dev-server-esbuild seems not to have an API for esbuild plugins, only loaders.

Whatever combination I try, nothing seems to work.

export default {
    nodeResolve: true,
    plugins: [esbuildPlugin({ ts: true, target: 'es2020' } ), sassPlugin({
        type: "lit-css",
    })],
}

or e.g.

export default {
    nodeResolve: true,
    plugins: [esbuildPlugin({ ts: true, target: 'es2020'‘, loaders: { '.scss': ' css' } } ), sassPlugin({
        type: "lit-css",
    })],
}

I also checked the source code. Didn’t found any API for esPlugins in esbuildPlugin.

LarsDenBakker commented 3 years ago

Ah, the plugin system for esbuild is pretty new we didn't add support for it yet. So that would be something to do.

manuel-di-iorio commented 3 years ago

I tried in this way without success, like wrote in the esbuild-sass-plugin readme:

web-test-runner.config.js

import { esbuildPlugin } from "@web/dev-server-esbuild";
import { sassPlugin } from "esbuild-sass-plugin";

export default {
  nodeResolve: true,
  plugins: [
    esbuildPlugin({
      ts: true,
      target: "auto",
      loaders: { ".scss": "css" },
      plugins: [sassPlugin({ type: "lit-css" })]
    })
  ],
};

style.scss

button {
  color: blue;
}

The WTR error is: 🚧 Browser logs: SyntaxError: Unexpected token '{' Not sure if this is related to esbuild or web-test-runner Are there updates on this issue?

ChristianUlbrich commented 2 years ago

Your best bet is, to simply run your WebPack build before running the tests, as @LarsDenBakker has suggested. That way you have one build toolchain. For unit tests this can be overly complex, because you'd only need the actual units under test instead of a whole bundle. However I am pretty sure WebPack can be coerced into doing so, i.e. generating individual .js files for each test as well.

We have a similar setup (LitElement + Sass), but we do not rely on any bundler at all - we simply use TypeScript directly. We solve Sass transpilation by a very basic TypeScript Transformer Plugin / Dev Server Plugin. Only production bundles are generated by Rollup after everything has been transpiled by TypeScript into ES(M) modules.

I'd try to stay with the same toolchains for testing + production as close as possible, because errors can get pretty complex very fast.

rlnas commented 1 year ago

Hi @ChristianUlbrich thanks for sharing. I'm trying your approach. But I'm not having much success. Was wondering if you have any project references, examples to follow. Currently my project just uses typescript, lit, vite, and sass.

gethari commented 8 months ago

Hi @ChristianUlbrich thanks for sharing. I'm trying your approach. But I'm not having much success. Was wondering if you have any project references, examples to follow. Currently my project just uses typescript, lit, vite, and sass.

by any chance did you solve this ?

ChristianUlbrich commented 8 months ago

@rlnas @gethari I do not know your build stack. The OP had Webpack in place. Things are a lot more different, than they used to be in 2021. Nowadays I'd suggest using https://open-wc.org/docs/development/generator/ as this sets up WTR properly or still stick to my advice:

Use the exact tool chain, that you are running to generate your production build to produce individual .test.js files that can be picked up by WTR.

I know this is tricky, if you are using SASS, because it involves at some point some kind of "magic" transpilation and it heavily depends, on how you actually consume SASS.

In our project, we were using SASS by directly importing it:

import style from './button.component.scss';
//...
const buttonStyles = css`
  ${unsafeCSS(style)}
`;

This works, by a very basic custom TypeScript transformer, that does transpile SASS to a proper JS string.

Usually it is a good idea, to use the testing setup that is causing the least trouble with the chosen build stack and furthermore it is usually a good idea, to use something battle-proven. So @rlnas in your case, if you are using already vite, go with vitest instead of wtr, although this kind of defeats the purpose of this question. :)

You can mix and match all kinds of stacks, but this involves additional work, that I can not describe more than I already have, I am afraid.

If I were to start again, I'd either use the generator and have wds + wtr or vite and vitest, but not a mixture of them. The choice of the test runner is not so important, the choice of the testing environment is. It does not make sense, to test Web Components in non-browser environments. So this means, either way, go with Playwright (wtr already uses Playwright).

gethari commented 8 months ago

@ChristianUlbrich thanks for responding.

The OP had Webpack in place

Me too :), my project is almost 3 years old & it is using webpack to bundle it. Initially I thought of migrating out of webpack to vite but it seems like a lot of work.

depends, on how you actually consume SASS.

we do this same thing as well , import style from './button.component.scss';

Usually it is a good idea, to use the testing setup that is causing the least trouble

I agree 👍 , but my application is 3 years old, what would be most efficient way to go about it ?

Right now, I added wtr+playwright & when I run tests, it results in Failed to load module, cannot seem to figure out the actual case, or is it easy to just migrate to vite +vitest ?

ChristianUlbrich commented 8 months ago

@gethari There is no easy way I am afraid. If this is for a commercial project, I'd gladly offer consulting service; this is something, that at least takes 2-3 days... webpack is a beast and while it was fun, I am glad its days are over.