t2ym / web-component-tester

Forked @t2ym/web-component-tester to work with wct-istanbul
https://github.com/t2ym/web-component-tester/tree/wct6-plugin-scoped
BSD 3-Clause "New" or "Revised" License
3 stars 3 forks source link

Create pull requests to merge the patches into the official web-component-tester #1

Open t2ym opened 7 years ago

t2ym commented 7 years ago

Create pull requests to merge the patches into the official web-component-tester

ToDos

t2ym commented 7 years ago

Related Issues

t2ym commented 7 years ago

Main diff for polyserve/istanbul git diff master src

diff --git a/src/cli.ts b/src/cli.ts
index 08623bf..c25c1cd 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -65,6 +65,7 @@ export async function run(): Promise<StartServerResult> {
     certPath: cliOptions['cert'],
     pushManifestPath: cliOptions['manifest'],
     proxy: proxyArgs.path && proxyArgs.target && proxyArgs,
+    wctPlugin: false
   };

   if (cliOptions.help) {
diff --git a/src/start_server.ts b/src/start_server.ts
index 1e70202..e7c4f0d 100644
--- a/src/start_server.ts
+++ b/src/start_server.ts
@@ -26,6 +26,9 @@ import * as url from 'url';
 import {babelCompile} from './compile-middleware';
 import {getComponentDir, getPackageName} from './config';
 import {injectCustomElementsEs5Adapter} from './custom-elements-es5-adapter-middleware';
+import {Request, Response} from 'express';
+import {parse as parseContentType} from 'content-type';
+import {transformResponse} from './transform-middleware';
 import {makeApp} from './make_app';
 import {openBrowser} from './util/open_browser';
 import {getPushManifest, pushResources} from './util/push';
@@ -100,6 +103,9 @@ export interface ServerOptions {
   /** An optional list of routes & route handlers to attach to the polyserve
    * app, to be handled before all others */
   additionalRoutes?: Map<string, express.RequestHandler>;
+
+  /** Allow Plug-in for WCT */
+  wctPlugin?: boolean
 }

 function applyDefaultServerOptions(options: ServerOptions) {
@@ -362,36 +368,58 @@ export function getApp(options: ServerOptions): express.Express {
     app.use(`/${escapedPath}/`, apiProxy);
   }

-  const forceCompile = options.compile === 'always';
-  if (options.compile === 'auto' || forceCompile) {
-    app.use('*', injectCustomElementsEs5Adapter(forceCompile));
-    app.use('*', babelCompile(forceCompile));
+  app['_delayedAppConfig'] = () => {
+
+    const forceCompile = options.compile === 'always';
+    if (options.compile === 'auto' || forceCompile) {
+      app.use('*', injectCustomElementsEs5Adapter(forceCompile));
+      app.use('*', babelCompile(forceCompile));
+    }
+
+    app.use('*', transformResponse({
+      shouldTransform(request: Request, response: Response): boolean {
+        const contentTypeHeader = response.getHeader('Content-Type');
+        const contentType = contentTypeHeader && parseContentType(contentTypeHeader).type;
+        return !!(request && contentType && contentType && contentType.match(/^(text\/|application\/javascript)/));
+      },
+      transform(request: Request, response: Response, body: string): string {
+        return request && response ? body : '';
+      },
+      last: true
+    }));
+
+    app.use(`/${componentUrl}/`, polyserve);
+
+    // `send` expects files to be specified relative to the given root and as a
+    // URL rather than a file system path.
+    const entrypoint =
+        options.entrypoint ? urlFromPath(root, options.entrypoint) : 'index.html';
+
+    app.get('/*', (req, res) => {
+      pushResources(options, req, res);
+      const filePath = req.path;
+      send(req, filePath, {root: root, index: entrypoint})
+          .on('error',
+              (error: send.SendError) => {
+                if ((error).status === 404 && !filePathRegex.test(filePath)) {
+                  // The static file handling middleware failed to find a file on
+                  // disk. Serve the entry point HTML file instead of a 404.
+                  send(req, entrypoint, {root: root}).pipe(res);
+                } else {
+                  res.statusCode = error.status || 500;
+                  res.end(error.message);
+                }
+              })
+          .pipe(res);
+    });
+
+    app['_delayedAppConfig'] = () => {};
+  }
+
+  if (!options.wctPlugin) {
+    app['_delayedAppConfig']();
   }

-  app.use(`/${componentUrl}/`, polyserve);
-
-  // `send` expects files to be specified relative to the given root and as a
-  // URL rather than a file system path.
-  const entrypoint =
-      options.entrypoint ? urlFromPath(root, options.entrypoint) : 'index.html';
-
-  app.get('/*', (req, res) => {
-    pushResources(options, req, res);
-    const filePath = req.path;
-    send(req, filePath, {root: root, index: entrypoint})
-        .on('error',
-            (error: send.SendError) => {
-              if ((error).status === 404 && !filePathRegex.test(filePath)) {
-                // The static file handling middleware failed to find a file on
-                // disk. Serve the entry point HTML file instead of a 404.
-                send(req, entrypoint, {root: root}).pipe(res);
-              } else {
-                res.statusCode = error.status || 500;
-                res.end(error.message);
-              }
-            })
-        .pipe(res);
-  });
   return app;
 }

diff --git a/src/transform-middleware.ts b/src/transform-middleware.ts
index a08a42e..21efda4 100644
--- a/src/transform-middleware.ts
+++ b/src/transform-middleware.ts
@@ -16,7 +16,7 @@ import {Request, RequestHandler, Response} from 'express';

 export function transformResponse(transformer: ResponseTransformer):
     RequestHandler {
-  return (req: Request, res: Response, next: () => void) => {
+  return transformer.last ? (req: Request, res: Response, next: () => void) => {
     let ended = false;

     const chunks: Buffer[] = [];
@@ -73,7 +73,15 @@ export function transformResponse(transformer: ResponseTransformer):
         const body = Buffer.concat(chunks).toString('utf8');
         let newBody = body;
         try {
-          newBody = transformer.transform(req, res, body);
+          let tmpBody = body;
+          if (Array.isArray(req['_transformers'])) {
+            req['_transformers'].forEach((_transformer: ResponseTransformer) => {
+              if (_transformer.shouldTransform(req, res)) {
+                tmpBody = _transformer.transform(req, res, tmpBody);
+              }
+            });
+          }
+          newBody = transformer.transform(req, res, tmpBody);
         } catch (e) {
           console.warn('Error', e);
         }
@@ -89,6 +97,13 @@ export function transformResponse(transformer: ResponseTransformer):
     };

     next();
+  } :
+  (req: Request, res: Response, next: () => void) => {
+    if (req && res) {
+      req['_transformers'] = req['_transformers'] || [];
+      req['_transformers'].push(transformer);
+    }
+    next();
   };
 }

@@ -100,4 +115,6 @@ export interface ResponseTransformer {
   shouldTransform(request: Request, response: Response): boolean;

   transform(request: Request, response: Response, body: string): string;
+
+  last?: boolean;
 }
t2ym commented 7 years ago

Main diff for web-component-tester/wct6-plugin-scoped:

git diff master browser runner/*[^d].ts

diff --git a/browser/clisocket.js b/browser/clisocket.js
index c55526b..d53c203 100644
--- a/browser/clisocket.js
+++ b/browser/clisocket.js
@@ -29,6 +29,7 @@ export default function CLISocket(browserId, socket) {
  *     interesting events back to the CLI runner.
  */
 CLISocket.prototype.observe = function observe(runner) {
+  this.writable = true;
   this.emitEvent('browser-start', {
     url: window.location.toString(),
   });
@@ -77,11 +78,91 @@ CLISocket.prototype.observe = function observe(runner) {
  * @param {*} data Additional data to pass with the event.
  */
 CLISocket.prototype.emitEvent = function emitEvent(event, data) {
-  this.socket.emit('client-event', {
-    browserId: this.browserId,
-    event:     event,
-    data:      data,
-  });
+  var self = this;
+  var isPolling = false;
+  var dataJSON = data ? JSON.stringify(data) : '';
+  var dataSize = dataJSON.length;
+  var chunkSize = 65536;
+  var chunks = [];
+  var chunk;
+  var eventId;
+  var transport;
+  if (this.socket.io &&
+      this.socket.io.engine &&
+      this.socket.io.engine.transport &&
+      this.socket.io.engine.transport.query &&
+      this.socket.io.engine.transport.query.transport === 'polling') {
+    isPolling = true;
+    this.eventQueue = this.eventQueue || [];
+  }
+  if (isPolling) {
+    eventId = this.browserId + ',' + event + ',' + Date.now();
+    if (dataSize > chunkSize) {
+      transport = this.socket.io.engine.transport;
+      while (dataJSON) {
+        chunks.push(dataJSON.substr(0, chunkSize));
+        dataJSON = dataJSON.substr(chunkSize);
+      }
+      function processEventQueue() {
+        var eventItem;
+        while (eventItem = self.eventQueue.shift()) {
+          self.socket.emit(eventItem.event, eventItem.data);
+          if (eventItem.event === 'client-event-fragment') {
+            break;
+          }
+        }
+        if (self.eventQueue.length === 0) {
+          self.writable = true;
+          transport.removeListener('drain', processEventQueue);
+        }
+      }
+      while (chunk = chunks.shift()) {
+        this.eventQueue.push({
+          event:   'client-event-fragment',
+          data: {
+            browserId: self.browserId,
+            eventId:   eventId,
+            event:     event,
+            chunk:     chunk,
+            last:      chunks.length === 0
+          }
+        });
+      }
+      if (this.writable) {
+        this.writable = false;
+        transport.on('drain', processEventQueue);
+        if (transport.writable) {
+          processEventQueue();
+        }
+      }
+    }
+    else {
+      if (this.writable) {
+        this.socket.emit('client-event', {
+          browserId: this.browserId,
+          event:     event,
+          data:      data,
+        });
+      }
+      else {
+        this.eventQueue.push({
+          event:   'client-event',
+          data: {
+            browserId: this.browserId,
+            event:     event,
+            data:      data,
+          }
+        });
+      }
+    }
+  }
+  else {
+    this.socket.emit('client-event', {
+      browserId: this.browserId,
+      event:     event,
+      data:      data,
+    });
+  }
 };

 /**
diff --git a/browser/suites.js b/browser/suites.js
index a18409c..605d954 100644
--- a/browser/suites.js
+++ b/browser/suites.js
@@ -30,7 +30,7 @@ export function loadSuites(files) {
   files.forEach(function(file) {
     if (/\.js(\?.*)?$/.test(file)) {
       jsSuites.push(file);
-    } else if (/\.html(\?.*)?$/.test(file)) {
+    } else if (/\.html(\?.*)?(#.*)?$/.test(file)) {
       htmlSuites.push(file);
     } else {
       throw new Error('Unknown resource type: ' + file);
diff --git a/runner/steps.ts b/runner/steps.ts
index b4899a5..8a46608 100644
--- a/runner/steps.ts
+++ b/runner/steps.ts
@@ -88,6 +88,7 @@ export async function runTests(context: Context): Promise<void> {
   context._socketIOServers = context._httpServers.map((httpServer) => {
     const socketIOServer = socketIO(httpServer);
     socketIOServer.on('connection', function(socket) {
+      let fragmentBuffer = {};
       context.emit('log:debug', 'Test client opened sideband socket');
       socket.on('client-event', function(data: ClientMessage<any>) {
         const runner = runners[data.browserId];
@@ -98,6 +99,21 @@ export async function runTests(context: Context): Promise<void> {
         }
         runner.onEvent(data.event, data.data);
       });
+      socket.on('client-event-fragment', function (data) {
+        const runner = runners[data.browserId];
+        if (!runner) {
+          throw new Error(
+              `Unable to find browser runner for ` +
+              `browser with id: ${data.browserId}`);
+        }
+        fragmentBuffer[data.eventId] = fragmentBuffer[data.eventId] || [];
+        fragmentBuffer[data.eventId].push(data.chunk);
+        if (data.last) {
+          data.data = JSON.parse(fragmentBuffer[data.eventId].join(''));
+          delete fragmentBuffer[data.eventId];
+          runner.onEvent(data.event, data.data);
+        }
+      });
     });
     return socketIOServer;
   });
diff --git a/runner/webserver.ts b/runner/webserver.ts
index 98d6061..7758272 100644
--- a/runner/webserver.ts
+++ b/runner/webserver.ts
@@ -134,6 +134,7 @@ Expected to find a ${mdFilenames.join(' or ')} at: ${pathToLocalWct}/

     // Serve up project & dependencies via polyserve
     const polyserveResult = await startServers({
+      wctPlugin: true,
       root: options.root,
       compile: options.compile,
       hostname: options.webserver.hostname,
@@ -176,6 +177,7 @@ Expected to find a ${mdFilenames.join(' or ')} at: ${pathToLocalWct}/
     // webservers as they please.
     for (const server of servers) {
       await wct.emitHook('prepare:webserver', server.app);
+      server.app['_delayedAppConfig']();
     }

     options.webserver._servers = servers.map(s => {
t2ym commented 7 years ago

Potential Design Issues

Documentation

Tests

t2ym commented 7 years ago

The patched version is available on NPM repository.

https://www.npmjs.com/package/@t2ym/web-component-tester

npm install --save-dev @t2ym/web-component-tester
npm install --save-dev wct-istanbul
bower install --save-dev t2ym/web-component-tester#^6.0.1
t2ym commented 7 years ago

It seems the main repository is undergoing major changes toward Polymer 3.0 with full NPM support. It has to be considered that this patching is conceptually compatible with the coming versions.