From b070fa3874c79f25d43ba666c6bcf38968f191ae Mon Sep 17 00:00:00 2001 From: Sibiraj Date: Wed, 21 Nov 2018 08:44:40 +0530 Subject: [PATCH] chore: add extension tests --- .travis.yml | 6 +- .vscode/launch.json | 16 +++ package-lock.json | 6 ++ package.json | 7 +- src/test/extension.test.ts | 54 +++++++++++ src/test/fixtures/ugly.css | 40 ++++++++ src/test/fixtures/ugly.scss | 187 ++++++++++++++++++++++++++++++++++++ src/test/index.ts | 22 +++++ 8 files changed, 334 insertions(+), 4 deletions(-) create mode 100644 src/test/extension.test.ts create mode 100644 src/test/fixtures/ugly.css create mode 100644 src/test/fixtures/ugly.scss create mode 100644 src/test/index.ts diff --git a/.travis.yml b/.travis.yml index 65c0068..574704c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,12 @@ branches: only: - master +before_script: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + install: - - npm install + - npm ci script: - npm run test diff --git a/.vscode/launch.json b/.vscode/launch.json index cecb5e8..28f70af 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,6 +13,22 @@ "${workspaceFolder}/out/**/*.js" ], "preLaunchTask": "npm: watch" + }, + { + "name": "Extension Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "${workspaceFolder}/src/test/", + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/out/test" + ], + "outFiles": [ + "${workspaceFolder}/out/test/**/*.js" + ], + "preLaunchTask": "npm: watch" } ] } diff --git a/package-lock.json b/package-lock.json index 5b1e2f2..0490842 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,12 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/mocha": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz", + "integrity": "sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww==", + "dev": true + }, "@types/node": { "version": "10.12.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.9.tgz", diff --git a/package.json b/package.json index d772060..eeeb77a 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,7 @@ "Formatters" ], "activationEvents": [ - "onLanguage:css", - "onLanguage:scss" + "*" ], "main": "./out/extension", "contributes": { @@ -51,7 +50,8 @@ "compile": "tsc -p ./", "lint": "tslint -p ./", "postinstall": "node ./node_modules/vscode/bin/install", - "test": "npm run lint", + "pretest": "npm run lint", + "test": "npm run compile && CODE_TESTS_WORKSPACE=src/test node ./node_modules/vscode/bin/test", "vscode:prepublish": "npm run compile", "watch": "tsc -watch -p ./" }, @@ -59,6 +59,7 @@ "prettier": "^1.15.2" }, "devDependencies": { + "@types/mocha": "^5.2.5", "@types/node": "^10.12.9", "husky": "^1.1.4", "tslint": "^5.11.0", diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts new file mode 100644 index 0000000..388841a --- /dev/null +++ b/src/test/extension.test.ts @@ -0,0 +1,54 @@ +/* tslint:disable: no-console */ +import * as assert from 'assert'; +import * as path from 'path'; +import { commands, Uri, window, workspace } from 'vscode'; + +const prettier = require('prettier'); + +/** + * loads and format a file. + * @param file path relative to base URI (a workspaceFolder's URI) + * @param base base URI + * @returns source code and resulting code + */ +async function format( + file: string, + base: Uri = workspace.workspaceFolders![0].uri +): Promise<{ + result: string; + source: string; +} | undefined> { + const absPath = path.join(base.fsPath, file); + const doc = await workspace.openTextDocument(absPath); + const text = doc.getText(); + try { + await window.showTextDocument(doc); + console.time(file); + await commands.executeCommand('editor.action.formatDocument'); + console.timeEnd(file); + return { result: doc.getText(), source: text }; + } catch (e) { + console.error(e); + return; + } +} + +/** + * Compare prettier's output (default settings) + * with the output from extension. + * @param file path relative to workspace root + */ +async function formatSameAsPrettier(file: string) { + const result = await format(file); + if (result) { + const prettierFormatted = prettier.format(result.source, { + filepath: file, + }); + assert.equal(result.result, prettierFormatted); + } +} + +suite('SCSS Formatter Extension Tests', () => { + test('it should fromat CSS', () => formatSameAsPrettier('fixtures/ugly.css')); + test('it should format SCSS', () => formatSameAsPrettier('fixtures/ugly.scss')); +}); diff --git a/src/test/fixtures/ugly.css b/src/test/fixtures/ugly.css new file mode 100644 index 0000000..01a4267 --- /dev/null +++ b/src/test/fixtures/ugly.css @@ -0,0 +1,40 @@ +:root { + font-size: 12px; + font-family: monospace; + --color: #FF555B; + --bg: #FDFDF2; +} + +* { margin: 0; + padding: 0; + box-sizing: border-box; user-select: none; -webkit-tap-highlight-color: transparent; +} + +html, body { + overflow: hidden; +} + +body { + width: 100vw; + height: 100vh; + color: var(--color); background-color: var(--bg); +} + +a { + color: inherit; +} svg { + display: block; + fill: currentColor; +} .credits { + position: fixed; + bottom: 1rem; right: 1rem; + font-size: 0.75rem; +} + +.credits > span { + display: flex; + align-items: center; + justify-content: flex-end; +} + +.hide { opacity: 0; } diff --git a/src/test/fixtures/ugly.scss b/src/test/fixtures/ugly.scss new file mode 100644 index 0000000..e831292 --- /dev/null +++ b/src/test/fixtures/ugly.scss @@ -0,0 +1,187 @@ +html { box-sizing: box-model; } +*, *:before, *:after { box-sizing: inherit; outline:0; } +header,main,nav,article,section,figure,figcaption,code{ display:block;position: relative; } + + +@mixin aspect-ratio($arglist... /*$width/$ratio, $height*/){ + $map : keywords($arglist); + $height: map-get($map, height) or nth-or-null($arglist, 2); + $width: map-get($map, width) or nth-or-null($arglist, 1); + $ratio: map-get($map, ratio) or if($width and $height, $width/$height, nth-or-null($arglist, 1)) or 1; + $padding: 1/$ratio * 100%; + &:before { content: ''; float:left; padding-bottom: $padding; } + &:after { content: ''; display:table; clear: both; } +} +// Helper function +// Return null rather than throwing an error if index is outside list range. +@function nth-or-null($list, $index) { + @return if(length($list) >= $index, nth($list, $index), null); +} + +// +// Function to create an optimized svg url +// +@function svg-url($svg){ + // + // Add missing namespace + // + @if not str-index($svg,xmlns) { + $svg: str-replace($svg, '', '%3E'); + + + $encoded: #{$encoded}#{$chunk}; + $index: $index + $slice; + } + @return url("data:image/svg+xml,#{$encoded}"); +} + + + +// Background svg mixin +@mixin background-svg($svg){ + background-image: svg-url($svg); +} + +// Helper function to replace characters in a string +@function str-replace($string, $search, $replace: '') { + $index: str-index($string, $search); + @return if($index, + str-slice($string, 1, $index - 1) + $replace + + str-replace(str-slice($string, $index + + str-length($search)), $search, $replace), + $string); +} + + + +$svg-cartman:''; + +.cartman { + @include aspect-ratio(); + width: 40%; + margin: 40px 0; + padding: 0; + position: relative; + @include background-svg($svg-cartman); // <= here :-) + background-size: cover; + background-repeat:no-repeat; + background-position:50% 50%; +} + +figcaption { + position:absolute; + display:block; + left: 100%; + &:before,&:after { + content:''; + position:absolute; + display:block; + } + &:before { + font:15px 'Comic Sans MS'; + content:'SVG in CSS freaking sucks ...Wait What!'; + text-transform:uppercase; + width:230px; + text-align:center; + border:1px solid #f1f1f1; + background:white; + border-radius:5px; + padding:20px; + } + &:after{ + top:75px; + left: 10px; + transform:rotate(30deg); + border-top:30px solid white; + border-left:10px solid transparent; + border-right:10px solid transparent; + } +} + +$logo-color : #00b8c4; +$body-color : whitesmoke; +$h1-color : #00b8c4; +$h2-color : #00b8c4; +$h3-color : #00b8c4; +$text-color : #282828; +$link-color : #00b8c4; + + +html { box-sizing: box-model; } +*, *:before, *:after { box-sizing: inherit; } +header,main,nav,article,section,figure,figcaption,code{ display:block;position: relative; } + + +@include google-font{ + @include google-font(Lato, 300 400 700); + @include google-font(Lato, 300 400 700, italic); + @include google-font('Playfair Display', $text: '“”‘’"\''); + @include google-font('Lateef'); +} + +p,label { font: 400 16px/1.3 'Lato', sans-serif; color: $text-color; } +h1 { font: 300 36px/1.3 'Lato', sans-serif; color: $h1-color; } +h2 { font: 300 24px/1.3 'Lato', sans-serif; color: $h2-color; } +[class*="example"] {font: 400 14px/1.3 'Lato', sans-serif; color: white; } +a {color: $link-color; text-decoration: none; &:hover,&:focus { + text-decoration: underline; +}} + +strong { font: inherit; font-weight: 700; } +em { font: inherit; font-style: italic; } +p { max-width: 700px; } +blockquote { + padding:0; margin:20px 0; + &:before { content: '“'; font-family: 'Playfair Display'; font-size:16px; } + &:after { content: '”'; font-family: 'Playfair Display'; font-size:16px; } +} +[data-related-pens] { background: $logo-color; } + + +body { + background: $body-color; +} +article { + margin:-20px auto 40px; + max-width: 900px; + border-radius: 7px; + padding: 20px 40px 0; + // background: white; + // box-shadow: 0 5px 5px rgba(0, 0, 0, 0.2); +} +section { margin: 40px 0; } + +textarea { + outline: 0; + margin-top: 8px; + width:100%; + height:200px; + background:whitesmoke; + border:1px solid #dddd; +} +input { margin-top: 8px; outline: 0; background:whitesmoke; font-size:20px; padding:10px; border:1px solid #dddd; display:block; +width:calc(100% - 20px); } +[for="pastezone"], +[for="peninclude"]{font-weight: 700; } diff --git a/src/test/index.ts b/src/test/index.ts new file mode 100644 index 0000000..81d324b --- /dev/null +++ b/src/test/index.ts @@ -0,0 +1,22 @@ +// +// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING +// +// This file is providing the test runner to use when running extension tests. +// By default the test runner in use is Mocha based. +// +// You can provide your own test runner if you want to override it by exporting +// a function run(testRoot: string, clb: (error:Error) => void) that the extension +// host can call to run the tests. The test runner is expected to use console.log +// to report the results back to the caller. When the tests are finished, return +// a possible error to the callback or null if none. + +import * as testRunner from 'vscode/lib/testrunner'; + +// You can directly control Mocha options by uncommenting the following lines +// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info +testRunner.configure({ + ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) + useColors: true // colored output from test results +}); + +module.exports = testRunner;