Skip to content

Commit

Permalink
Pass in output path with Python script
Browse files Browse the repository at this point in the history
Uses default location when run from within Sketch
  • Loading branch information
christianklotz committed Mar 2, 2021
1 parent 3a038c1 commit 81a251f
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 22 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ These integration tests are compiled into a single test plugin using Webpack and
**Build test plugin**
To build the plugin separately, e.g. to install and run it manually, run this command:
To build the plugin separately, e.g. to install and run it manually, run the following command.
```sh
npm install # if you haven't installed dependencies already
npm run test:build --identifier=IDENTIFIER --output=FILE_PATH
npm run test:build --identifier=IDENTIFIER
```
To build the plugin including only one spec file, e.g. run tests from one spec only, run this command:
Expand All @@ -126,13 +126,13 @@ To build the plugin including only one spec file, e.g. run tests from one spec o
npm run test:build --identifier=IDENTIFIER --output=FILE_PATH --spec=SpecFileName.test.js
```

The output `FILE_PATH` is "baked" into the plugin. Test results are always written to the same file, overwriting any previous contents. Use different `IDENTIFIER` values if you are testing different versions of Sketch or want to run integration tests concurrently on the same machine.
Use different `IDENTIFIER` values if you are testing different versions of Sketch or want to run integration tests concurrently on the same machine.

> **Note:** The Sketch JavaScript API does not need to be rebuilt. The integration tests use the API bundled within Sketch or the custom API location specified in the user defaults.
**Run test plugin**

To run the integration test plugin from the command-line, you must provide the path to the plugin and the same output file path specified at build-time of the plugin.
To run the integration test plugin from the command-line, you must provide the path to the plugin and a file path to be used by the plugin to write the test results and can be watched by the Python script for changes.

```sh
python run_tests.py -p /path/to/SketchIntegrationTests-$UUID.sketchplugin -o FILE_PATH [-s SKETCH_PATH]
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"homepage": "https://github.com/sketch-hq/SketchAPI",
"scripts": {
"build": "./build.sh",
"test:build": "webpack --config webpack.tests.config.js --env.identifier=$npm_config_identifier --env.output=$npm_config_output --env.spec=$npm_config_spec",
"test:build": "webpack --config webpack.tests.config.js --env.identifier=$npm_config_identifier --env.spec=$npm_config_spec",
"lint": "eslint \"Source/**\"",
"format-check": "prettier --check \"**/*.{js,json}\"",
"api-location:write": "defaults write com.bohemiancoding.sketch3 SketchAPILocation \"$(pwd)/build\"",
Expand Down
18 changes: 12 additions & 6 deletions run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ def terminate_process(path):

try:
exe = proc.exe()
except psutil.AccessDenied:
continue
except Exception as e:
print(f"Could not get executable for process {pid}: {e}", file=sys.stderr)
continue
Expand Down Expand Up @@ -191,11 +193,11 @@ def main(argv):
print(usage)
sys.exit()
elif opt in ("-s", "--sketch"):
sketch = arg
sketch = Path(arg).expanduser().resolve()
elif opt in ("-p", "--plugin"):
plugin = Path(arg).resolve()
plugin = Path(arg).expanduser().resolve()
elif opt in ("-o", "--outputFilePath"):
output_file_path = Path(arg).resolve()
output_file_path = Path(arg).expanduser().resolve()
elif opt in ("-t", "--timeout"):
timeout = float(arg)

Expand All @@ -204,9 +206,13 @@ def main(argv):
sys.exit(2)

if not os.path.exists(plugin):
print(f"Plugin does not exist at: {plugin}", file=sys.stderr)
print(f"Plugin not found at: {plugin}", file=sys.stderr)
sys.exit(2)


if not os.path.exists(sketch):
print(f"Sketch bundle not found at: {sketch}", file=sys.stderr)
sys.exit(2)

# create a symbolic link to the plugin because Sketch expects it to
# be inside the Application Support Plugins folder.
plugin_path = PurePath(
Expand Down Expand Up @@ -241,7 +247,7 @@ def main(argv):
# windows, wait for Sketch to quit and use specific path to Sketch app
subprocess.Popen([
"open", "-nFa", sketch,
f"sketch://plugin/{manifest['identifier']}/test",
f"sketch://plugin/{manifest['identifier']}/test?output={output_file_path}",
])

try:
Expand Down
29 changes: 18 additions & 11 deletions webpack.tests.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const findTestSuites = (spec) => {
*
* @param {Object[]} tests An array of test suites to run.
*/
function source(tests, output) {
function source(identifier, tests) {
// The test suites are build up by `test` function within unit tests
// and have the following structure:
//
Expand Down Expand Up @@ -260,12 +260,20 @@ function source(tests, output) {
const prepareStackTrace = require('sketch-utils/prepare-stack-trace')
const fileManager = NSFileManager.defaultManager()
const out = '${path.resolve(output)}'
// Use a default path for the test results if not specified by the user,
// for instance when running the test plugin from the Sketch app menu.
const {
actionContext: {
query: {
output = path.resolve(os.tmpdir(), "SketchIntegrationTests-${identifier}.log")
},
},
} = { actionContext: { query: { output: undefined}}, ...context }
// Create the results file and write extended file attributes with zero
// progress information
fileManager.createFileAtPath_contents_attributes(
out,
output,
nil,
attributes(0),
)
Expand All @@ -279,7 +287,7 @@ function source(tests, output) {
onProgress: (fraction) => { // update the extended file attributes
fileManager.setAttributes_ofItemAtPath_error(
attributes(fraction),
out,
output,
nil,
)
},
Expand All @@ -290,13 +298,13 @@ function source(tests, output) {
const err = MOPointer.alloc().init()
data.writeToFile_atomically_encoding_error(
out,
output,
false,
NSUTF8StringEncoding,
err
)
console.log('✅ Test results saved to: ' + out)
console.log('✅ Test results saved to: ' + output)
sketch.UI.message('✅ Test results saved to disk.')
}
`
Expand All @@ -307,14 +315,13 @@ const { NODE_ENV } = process.env
/**
* Creates webpack configuration
*/
let src = (output, spec) => source(findTestSuites(spec), output)
let src = (identifier, spec) => source(identifier, findTestSuites(spec))

module.exports = ({ identifier, output, spec }) => {
module.exports = ({ identifier, spec }) => {
// To allow multiple instances of Sketch to run API tests concurrently
// the plugin must use a unique name and plugin identifier.
//
// The `identifier` and `output` parameters are passed in from the
// command-line.
// The `identifier` parameter is passed in from the command-line.
//
// The plugin itself is written to the build artefacts and can be used
// from there by copying into:
Expand Down Expand Up @@ -381,7 +388,7 @@ module.exports = ({ identifier, output, spec }) => {
plugins: [
// All __tests__/*.test.js files are gathered and bundled as a single plugin.
new VirtualModulesPlugin({
'./tests.js': src(output, spec),
'./tests.js': src(identifier, spec),
}),
new CopyPlugin({
patterns: [
Expand Down

0 comments on commit 81a251f

Please sign in to comment.