Skip to content

Commit

Permalink
test: stabilize e2e tests on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-oles committed May 20, 2020
1 parent 6052b66 commit 25e1e54
Show file tree
Hide file tree
Showing 18 changed files with 210 additions and 855 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
strategy:
matrix:
node: [10, 12] # add 14 when we drop support for webpack 4 as fsevents 1 is not compatible with node 14
os: [ubuntu-latest, macos-latest] # add windows-latest when e2e tests on other platforms will be stable
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v1

Expand Down
22 changes: 9 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@
"main": "lib/index.js",
"types": "lib/index.d.ts",
"scripts": {
"build": "rimraf lib && tsc --version && tsc",
"lint": "eslint ./src ./test --ext .ts",
"build": "cross-env rimraf lib && cross-env tsc --version && cross-env tsc",
"lint": "cross-env eslint ./src ./test --ext .ts",
"test": "yarn build && yarn test:unit && yarn test:e2e",
"test:unit": "jest unit",
"test:e2e": "yarn pack --filename fork-ts-checker-webpack-plugin.tgz && jest e2e --ci --runInBand --bail --verbose",
"precommit": "lint-staged && yarn build && yarn test:unit",
"commit": "./node_modules/.bin/git-cz"
"test:unit": "cross-env jest unit",
"test:pack": "yarn pack --filename fork-ts-checker-webpack-plugin.tgz",
"test:e2e": "yarn test:pack && cross-env jest e2e --ci --runInBand --bail --verbose",
"precommit": "cross-env lint-staged && yarn build && yarn test:unit",
"commit": "cross-env git-cz"
},
"husky": {
"hooks": {
Expand Down Expand Up @@ -70,7 +71,6 @@
},
"devDependencies": {
"@commitlint/config-conventional": "^8.3.4",
"@mdx-js/mdx": "^1.5.8",
"@types/babel__code-frame": "^7.0.1",
"@types/cross-spawn": "^6.0.2",
"@types/eslint": "^6.8.0",
Expand All @@ -86,6 +86,7 @@
"@typescript-eslint/eslint-plugin": "^2.27.0",
"@typescript-eslint/parser": "^2.27.0",
"commitlint": "^8.3.5",
"cross-env": "^7.0.2",
"cross-spawn": "^7.0.2",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.1",
Expand All @@ -96,18 +97,13 @@
"jest": "^25.3.0",
"lint-staged": "^10.1.3",
"mock-fs": "^4.11.0",
"nativescript-vue-template-compiler": "^2.5.1",
"prettier": "^2.0.4",
"rimraf": "^3.0.2",
"strip-ansi": "^6.0.0",
"tree-kill": "^1.2.2",
"ts-jest": "^25.3.1",
"ts-loader": "^6.2.2",
"typescript": "^3.8.3",
"unixify": "^1.0.0",
"vue": "^2.6.11",
"vue-class-component": "^7.2.3",
"vue-loader": "^15.9.1",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.42.1"
},
"engines": {
Expand Down
3 changes: 2 additions & 1 deletion src/formatter/WebpackFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import chalk from 'chalk';
import { relative } from 'path';
import { Formatter } from './Formatter';
import { formatIssueLocation } from '../issue';
import normalizeSlash from '../utils/path/normalizeSlash';

function createWebpackFormatter(formatter: Formatter, context: string): Formatter {
return function webpackFormatter(issue) {
const severity = issue.severity.toUpperCase();
const file = issue.file ? relative(context, issue.file) : undefined;
const file = issue.file ? normalizeSlash(relative(context, issue.file)) : undefined;
const location = issue.location ? formatIssueLocation(issue.location) : undefined;
const color = issue.severity === 'warning' ? chalk.yellow : chalk.red;
const header = [severity, 'in', file].concat(location ? [location] : []).join(' ');
Expand Down
19 changes: 17 additions & 2 deletions src/hooks/getChangedFiles.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import webpack from 'webpack';
import path from 'path';
import { getWatcher } from './getWatcher';

function getChangedFiles(compiler: webpack.Compiler): string[] {
let changedFiles: string[] = [];

if ((compiler as any).modifiedFiles) {
// webpack 5+
return Array.from((compiler as any).modifiedFiles);
changedFiles = Array.from((compiler as any).modifiedFiles);
} else {
const watcher = getWatcher(compiler);
// webpack 4
return Object.keys((watcher && watcher.mtimes) || {});
changedFiles = Object.keys((watcher && watcher.mtimes) || {});
}

return (
changedFiles
// normalize paths
.map((changedFile) => path.normalize(changedFile))
// check if path is inside the context to filer-out some trash from fs
.filter(
(changedFile) =>
!compiler.options.context ||
changedFile.startsWith(path.normalize(compiler.options.context))
)
);
}

export { getChangedFiles };
19 changes: 17 additions & 2 deletions src/hooks/getDeletedFiles.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import webpack from 'webpack';
import path from 'path';
import { ForkTsCheckerWebpackPluginState } from '../ForkTsCheckerWebpackPluginState';

function getDeletedFiles(
compiler: webpack.Compiler,
state: ForkTsCheckerWebpackPluginState
): string[] {
let deletedFiles: string[] = [];

if ((compiler as any).removedFiles) {
// webpack 5+
return Array.from((compiler as any).removedFiles || []);
deletedFiles = Array.from((compiler as any).removedFiles || []);
} else {
// webpack 4
return [...state.removedFiles];
deletedFiles = [...state.removedFiles];
}

return (
deletedFiles
// normalize paths
.map((changedFile) => path.normalize(changedFile))
// check if path is inside the context to filer-out some trash from fs
.filter(
(changedFile) =>
!compiler.options.context ||
changedFile.startsWith(path.normalize(compiler.options.context))
)
);
}

export { getDeletedFiles };
3 changes: 2 additions & 1 deletion src/issue/IssueWebpackError.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { relative } from 'path';
import { Issue } from './Issue';
import { formatIssueLocation } from './IssueLocation';
import normalizeSlash from '../utils/path/normalizeSlash';

class IssueWebpackError extends Error {
readonly hideStack = true;
Expand All @@ -13,7 +14,7 @@ class IssueWebpackError extends Error {
// should be a NormalModule instance.
// to avoid such a dependency, we do a workaround - error.file will contain formatted location instead
if (issue.file) {
const parts = [relative(context, issue.file)];
const parts = [normalizeSlash(relative(context, issue.file))];
if (issue.location) {
parts.push(formatIssueLocation(issue.location));
}
Expand Down
11 changes: 7 additions & 4 deletions src/typescript-reporter/TypeScriptReporterConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
createTypeScriptPnpExtensionConfiguration,
TypeScriptPnpExtensionConfiguration,
} from './extension/pnp/TypeScriptPnpExtensionConfiguration';
import normalizeSlash from '../utils/path/normalizeSlash';

interface TypeScriptReporterConfiguration {
enabled: boolean;
Expand Down Expand Up @@ -53,10 +54,12 @@ function createTypeScriptReporterConfiguration(
},
};

// ensure that `typescript.tsconfig` is an absolute path
configuration.tsconfig = path.isAbsolute(configuration.tsconfig)
? configuration.tsconfig
: path.resolve(compiler.options.context || process.cwd(), configuration.tsconfig);
// ensure that `typescript.tsconfig` is an absolute path with normalized slash
configuration.tsconfig = normalizeSlash(
path.isAbsolute(configuration.tsconfig)
? configuration.tsconfig
: path.resolve(compiler.options.context || process.cwd(), configuration.tsconfig)
);

return configuration;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import {
createTypeScriptEmbeddedExtension,
TypeScriptEmbeddedSource,
} from '../TypeScriptEmbeddedExtension';
import * as vueCompiler from 'vue-template-compiler';
import fs from 'fs-extra';
import { TypeScriptExtension } from '../TypeScriptExtension';
import { TypeScriptVueExtensionConfiguration } from './TypeScriptVueExtensionConfiguration';
import { VueTemplateCompiler } from './types/vue-template-compiler';

function createTypeScriptVueExtension(
configuration: TypeScriptVueExtensionConfiguration
): TypeScriptExtension {
function loadVueCompiler(): typeof vueCompiler {
function loadVueCompiler(): VueTemplateCompiler {
return require(configuration.compiler);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@
* This declaration is copied from https://github.com/vuejs/vue/pull/7918
* which may included vue-template-compiler v2.6.0.
*/
declare module 'vue-template-compiler' {
interface SFCParserOptions {
pad?: true | 'line' | 'space';
}
interface SFCParserOptions {
pad?: true | 'line' | 'space';
}

export interface SFCBlock {
type: string;
content: string;
attrs: Record<string, string>;
start?: number;
end?: number;
lang?: string;
src?: string;
scoped?: boolean;
module?: string | boolean;
}
export interface SFCBlock {
type: string;
content: string;
attrs: Record<string, string>;
start?: number;
end?: number;
lang?: string;
src?: string;
scoped?: boolean;
module?: string | boolean;
}

export interface SFCDescriptor {
template: SFCBlock | undefined;
script: SFCBlock | undefined;
styles: SFCBlock[];
customBlocks: SFCBlock[];
}
export interface SFCDescriptor {
template: SFCBlock | undefined;
script: SFCBlock | undefined;
styles: SFCBlock[];
customBlocks: SFCBlock[];
}

export function parseComponent(file: string, options?: SFCParserOptions): SFCDescriptor;
export interface VueTemplateCompiler {
parseComponent(file: string, options?: SFCParserOptions): SFCDescriptor;
}
53 changes: 31 additions & 22 deletions src/typescript-reporter/reporter/ControlledTypeScriptSystem.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as ts from 'typescript';
import { posix } from 'path';
import { dirname } from 'path';
import { createPassiveFileSystem } from './PassiveFileSystem';
import normalizeSlash from '../../utils/path/normalizeSlash';

interface ControlledTypeScriptSystem extends ts.System {
// control watcher
Expand Down Expand Up @@ -49,48 +50,56 @@ function createControlledTypeScriptSystem(): ControlledTypeScriptSystem {
path: string,
callback: TCallback
) {
const watchers = watchersMap.get(path) || [];
const normalizedPath = fileSystem.normalizePath(path);

const watchers = watchersMap.get(normalizedPath) || [];
const nextWatchers = [...watchers, callback];
watchersMap.set(path, nextWatchers);
watchersMap.set(normalizedPath, nextWatchers);

return {
close: () => {
const watchers = watchersMap.get(path) || [];
const watchers = watchersMap.get(normalizedPath) || [];
const nextWatchers = watchers.filter((watcher) => watcher !== callback);

if (nextWatchers.length > 0) {
watchersMap.set(path, nextWatchers);
watchersMap.set(normalizedPath, nextWatchers);
} else {
watchersMap.delete(path);
watchersMap.delete(normalizedPath);
}
},
};
}

const invokeFileWatchers = (path: string, event: ts.FileWatcherEventKind) => {
const fileWatchers = fileWatchersMap.get(path);
const normalizedPath = fileSystem.normalizePath(path);

const fileWatchers = fileWatchersMap.get(normalizedPath);
if (fileWatchers) {
fileWatchers.forEach((fileWatcher) => fileWatcher(path, event));
// typescript expects normalized paths with posix forward slash
fileWatchers.forEach((fileWatcher) => fileWatcher(normalizeSlash(normalizedPath), event));
}
};

const invokeDirectoryWatchers = (path: string) => {
let directory = posix.dirname(path);
const normalizedPath = fileSystem.normalizePath(path);
let directory = dirname(normalizedPath);

const directoryWatchers = directoryWatchersMap.get(directory);
if (directoryWatchers) {
directoryWatchers.forEach((directoryWatcher) => directoryWatcher(path));
directoryWatchers.forEach((directoryWatcher) =>
directoryWatcher(normalizeSlash(normalizedPath))
);
}

while (directory !== posix.dirname(directory)) {
while (directory !== dirname(directory)) {
const recursiveDirectoryWatchers = recursiveDirectoryWatchersMap.get(directory);
if (recursiveDirectoryWatchers) {
recursiveDirectoryWatchers.forEach((recursiveDirectoryWatcher) =>
recursiveDirectoryWatcher(path)
recursiveDirectoryWatcher(normalizeSlash(normalizedPath))
);
}

directory = posix.dirname(directory);
directory = dirname(directory);
}
};

Expand Down Expand Up @@ -128,7 +137,7 @@ function createControlledTypeScriptSystem(): ControlledTypeScriptSystem {
createDirectory(path: string): void {
fileSystem.createDir(path);

invokeDirectoryWatchers(fileSystem.normalizePath(path));
invokeDirectoryWatchers(path);
},
getDirectories(path: string): string[] {
const dirents = fileSystem.readDir(path);
Expand All @@ -145,11 +154,11 @@ function createControlledTypeScriptSystem(): ControlledTypeScriptSystem {
setModifiedTime(path: string, date: Date): void {
fileSystem.updateTimes(path, date, date);

invokeDirectoryWatchers(fileSystem.normalizePath(path));
invokeFileWatchers(fileSystem.normalizePath(path), ts.FileWatcherEventKind.Changed);
invokeDirectoryWatchers(path);
invokeFileWatchers(path, ts.FileWatcherEventKind.Changed);
},
watchFile(path: string, callback: ts.FileWatcherCallback): ts.FileWatcher {
return createWatcher(fileWatchersMap, fileSystem.normalizePath(path), callback);
return createWatcher(fileWatchersMap, path, callback);
},
watchDirectory(
path: string,
Expand All @@ -158,7 +167,7 @@ function createControlledTypeScriptSystem(): ControlledTypeScriptSystem {
): ts.FileWatcher {
return createWatcher(
recursive ? recursiveDirectoryWatchersMap : directoryWatchersMap,
fileSystem.normalizePath(path),
path,
callback
);
},
Expand Down Expand Up @@ -187,18 +196,18 @@ function createControlledTypeScriptSystem(): ControlledTypeScriptSystem {
invokeDirectoryWatchers(normalizedPath);

if (deletedFiles.get(normalizedPath)) {
invokeFileWatchers(normalizedPath, ts.FileWatcherEventKind.Created);
invokeFileWatchers(path, ts.FileWatcherEventKind.Created);
deletedFiles.set(normalizedPath, false);
} else {
invokeFileWatchers(normalizedPath, ts.FileWatcherEventKind.Changed);
invokeFileWatchers(path, ts.FileWatcherEventKind.Changed);
}
},
invokeFileDeleted(path: string) {
const normalizedPath = fileSystem.normalizePath(path);

if (!deletedFiles.get(normalizedPath)) {
invokeDirectoryWatchers(normalizedPath);
invokeFileWatchers(normalizedPath, ts.FileWatcherEventKind.Deleted);
invokeDirectoryWatchers(path);
invokeFileWatchers(path, ts.FileWatcherEventKind.Deleted);

deletedFiles.set(normalizedPath, true);
}
Expand Down
Loading

0 comments on commit 25e1e54

Please sign in to comment.