Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"presets": [
[
"@babel/env",
{
"targets": {
"safari": 17
}
}
]
]
}
6 changes: 5 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
],
"plugins": ["import"],
"parserOptions": {
"ecmaVersion": 9,
"ecmaVersion": 2020,
"sourceType": "module"
},
"env": {
Expand Down Expand Up @@ -43,6 +43,7 @@
"NSImage": "readonly",
"NSTextField": "readonly",
"NSSlider": "readonly",
"MSStyleBlur": "readonly",
"MSStyleFill": "readonly",
"MSStyleBorder": "readonly",
"MSColor": "readonly",
Expand Down Expand Up @@ -71,6 +72,7 @@
"NSString": "readonly",
"MSForeignSymbolProvider": "readonly",
"MSForeignObjectCollector": "readonly",
"MSStyleCorners": "readonly",
"MSStyleShadow": "readonly",
"MSGradientStop": "readonly",
"MSImmutableGradientStop": "readonly",
Expand Down Expand Up @@ -176,6 +178,8 @@
"NSMutableDictionary": "readonly",
"NSDictionary": "readonly",
"SmartLayout": "readonly",
"StackLayout": "readonly",
"MSFlexGroupLayout": "readonly",
"MSInferredGroupLayout": "readonly",
"MSFreeformGroupLayout": "readonly",
"MSSwatch": "readonly",
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
lts/*
22.17.0
106 changes: 91 additions & 15 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -1,59 +1,129 @@
{
"version": "2.0.0",
"tasks": [
//
// Build & Lint
//
{
"label": "Build & lint",
"label": "Build & Lint",
"group": {
"kind": "build",
"isDefault": true
},
"dependsOrder": "sequence",
"dependsOn": ["Lint", "Build"]
"dependsOn": ["Build", "Lint"]
},
{
"label": "Build",
"type": "npm",
"hide": true,
"script": "build",
"group": {
"kind": "build"
"presentation": {
"clear": true
}
},
{
"label": "Lint",
"type": "npm",
"script": "lint",
"group": {
"kind": "build"
}
"hide": true,
"script": "lint"
},
//
// Test
//
{
"label": "Build and run tests",
"label": "Test",
"dependsOrder": "sequence",
"dependsOn": ["Build", "Please choose target Xcode variant", "Run tests"],
"dependsOn": ["Build & Lint", "Test Default"],
"group": {
"kind": "test",
"isDefault": true
}
},
{
"label": "Please choose target Xcode variant",
"label": "Test Default",
"type": "npm",
"hide": true,
"script": "test"
},
//
// Test (single test suite)
//
{
"label": "Test [Single Suite]",
"dependsOrder": "sequence",
"dependsOn": [
"[Show the test suite name prompt]",
"Build & Lint",
"Test Single Suite"
],
"group": {
"kind": "test"
}
},
{
"label": "[Show the test suite name prompt]",
"type": "shell",
"command": "echo -e '\\033[0;34m=====================================================================\nSelect the Sketch variant to test against in the VSCode popup above ☝️\n(or just press Enter)\n=====================================================================\\033[0m'",
"hide": true,
"command": "echo",
"options": {
"env": {
"TEST_SUITE": "${input:testSuite}"
}
}
},
{
"label": "Test Single Suite",
"type": "npm",
"hide": true,
"script": "test:suite",
"options": {
"env": {
"TEST_SUITE": "${input:testSuite}"
}
}
},
//
// Test (custom Sketch target)
//
{
"label": "Test [Custom Sketch]",
"dependsOrder": "sequence",
"dependsOn": [
"[Show target Sketch variant prompt]",
"Build & Lint",
"Test Sketch Variant"
],
"group": {
"kind": "test"
}
},
{
"label": "Run tests",
"label": "[Show target Sketch variant prompt]",
"type": "shell",
"hide": true,
"command": "echo",
"options": {
"env": {
"SKETCH_VARIANT_BUNDLE_ID": "${input:sketchTarget}"
}
}
},
{
"label": "Test Sketch Variant",
"type": "npm",
"script": "test",
"script": "test:custom",
"hide": true,
"options": {
"env": {
"TARGET_SKETCH_VARIANT_BUNDLE_ID": "${input:sketchTarget}"
"SKETCH_VARIANT_BUNDLE_ID": "${input:sketchTarget}"
}
}
}
],
//
// [INPUTS]
//
"inputs": [
{
"id": "sketchTarget",
Expand All @@ -65,6 +135,12 @@
"com.bohemiancoding.sketch3"
],
"default": "com.bohemiancoding.sketch3.xcode"
},
{
"id": "testSuite",
"description": "Enter the test suite name:",
"type": "promptString",
"default": ""
}
]
}
58 changes: 49 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ sel.forEach(function (elem) {

### Prerequisits

- Have [Node](https://nodejs.org) installed
- Have [Node](https://nodejs.org) 22+ installed
- [Visual Studio Code](https://code.visualstudio.com) (recommended)

### Overview
Expand All @@ -62,21 +62,33 @@ The Sketch API is written in JavaScript/CocoaScript and gets bundled as part of
In addition to the API, this project also defines core modules to be included in Sketch as part of the official release process. Both are written to the `build` output folder when the build script is run:

```sh
npm install
./build.sh
```

#### Scripts

The following npm scripts are available for development of the API.

| Script | Description |
| ----------------------------- | --------------------------------------- |
| `npm run build` | Build SketchAPI into the `build` folder |
| `npm run test:build` | Build integration test plugin |
| `npm run lint` | Lint the source code |
| `npm run format-check` | Check the format with Prettier |
| `npm run api-location:write` | Tell Sketch to use your local SketchAPI |
| `npm run api-location:delete` | Undo `npm run api-location:write` |
| Script | Description |
| ----------------------------- | ------------------------------------------- |
| `npm run build` | Build SketchAPI into the `build` folder |
| `npm run test [suite]` | Run integrations tests (or a single suite). |
| `npm run lint` | Lint the source code |
| `npm run format-check` | Check the format with Prettier |
| `npm run api-location:write` | Tell Sketch to use your local SketchAPI |
| `npm run api-location:delete` | Undo `npm run api-location:write` |

In case you're using Visual Studio Code to work on SketchAPI, this project's `tasks.json` define the following shortcuts, available via _Command Palette > Run Task_:

| Task | Description |
| --- | --- |
| `Build & Lint` | Build SketchAPI and lint the source code |
| `Test` | Build SketchAPI and run integration tests |
| `Test [Single Suite]` | Build SketchAPI and run a select test suite |
| `Test [Custom Sketch]` | Build SketchAPI and run tests against a selected Sketch variant (e.g. Sketch Beta) |

The last two tasks will prompt you for a test suite name, or a Sketch bundleID respectively.

### Build and run

Expand Down Expand Up @@ -111,6 +123,32 @@ The SketchAPI builds on top of macOS and internal Sketch APIs via CocoaScript. T

These integration tests are compiled into a single test plugin using Webpack and can run by the `run_tests.py` Python script, or from the Sketch application menu.

> [!TIP]
> Install the `psutil` Python module, so that the test runner can terminate Sketch automatically upon test completion:
>
> ```
> pip install psutil
> ```
>
> Otherwise every new test run will leave a new instance of Sketch app hanging around.

All the necessary plumbing is done automatically when you run:

```sh
./test.sh
```

which optionally takes a name of the test suite to be run exclusively:

```sh
./test.sh SymbolInstance
```

This will build SketchAPI and tests, prepare the host plugin, set up your environment for testing, launch Sketch, and run the test suite in it, collecting and reporting the results back to you.

<details>
<summary>(Alternative) Manual steps to build and run tests</summary>

**Build test plugin**

To build the plugin separately, e.g. to install and run it manually, run the following command.
Expand Down Expand Up @@ -150,6 +188,8 @@ Tests can also be run manually from within Sketch:

The test results are written to the specified output file or, if no dedicated path is provided, to a temporary file. Use macOS' _Console.app_ to view Sketch's logs containing information on the file location and test progress in general.

</details>

## Acknowledgements

We would like to thank:
Expand Down
File renamed without changes.
41 changes: 41 additions & 0 deletions Scripts/build_sketch_api.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
EXIT_VALUE=0
LEVEL="warning"
if [[ "$BC_EXTERNAL_BUILD" == "YES" ]]; then
EXIT_VALUE=1
LEVEL="error"
fi

# First step is to to install node.
# We need to get a specific version of node installed and to do that we use nvm
# nvm is installed by Chef via brew. The default location is $HOME/.nvm
# Before we can run nvm, we need to source this profile in order to get its
# paths and envvars set up.

# Set NVM_DIR to the standard installation location within the user's home directory.
export NVM_DIR="$HOME/.nvm"

# Source NVM script to make 'nvm' commands available.
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

# Install the Node.js version specified by NVM (e.g., via .nvmrc or default)
nvm install
echo "note: Using node `node -v` from `which node`"

echo "note: Running npm install."
npm ci
RETVAL=$?
if [[ $RETVAL -ne 0 ]]; then
echo "${FULL_PRODUCT_NAME}:${LINENO}:1: ${LEVEL}: npm ci failed. Aborting SketchAPI build."
exit $EXIT_VALUE
fi

echo "note: Executing npm run build."
npm run build
RETVAL=$?
if [[ $RETVAL -ne 0 ]]; then
echo "${FULL_PRODUCT_NAME}:${LINENO}:1: ${LEVEL}: npm run build failed. Aborting SketchAPI build."
exit $EXIT_VALUE
fi

echo "project dir: $PROJECT_DIR"
echo "source dir: $SOURCE_ROOT"
53 changes: 53 additions & 0 deletions Scripts/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/bin/bash

TEST_RUN_ID=$(uuidgen)

# This script accepts one optional argument:
# - a name of a single test suite/spec, to only run this test suite and skip the rest
# e.g. "test.sh SymbolInstance". This option is also available as TEST_SUITE env variable
#
# There's also an optional SKETCH_VARIANT_BUNDLE_ID env variable indicating which Xcode
# variant to run tests against:
# - com.bohemiancoding.sketch3 (default if unset)
# - com.bohemiancoding.sketch3.beta
# - com.bohemiancoding.sketch3.xcode
if [[ -n "$1" ]]; then
TEST_SUITE_WEBPACK_ARG="--env spec=$1"
fi
if [ -n "${TEST_SUITE}" ]; then
TEST_SUITE_WEBPACK_ARG="--env spec=$TEST_SUITE"
fi

if [ -z "${SKETCH_VARIANT_BUNDLE_ID}" ]; then
SKETCH_VARIANT_BUNDLE_ID="com.bohemiancoding.sketch3"
fi

# Gracefully tear down the test env on error
tear_down() {
defaults delete "${SKETCH_VARIANT_BUNDLE_ID}" SketchAPILocation
}
trap 'tear_down' ERR

# Set up test environment
defaults write "${SKETCH_VARIANT_BUNDLE_ID}" SketchAPILocation -string "$(pwd)/build"

# Build tests
# shellcheck disable=SC2086
npx webpack --config webpack.tests.config.js --env identifier="$TEST_RUN_ID" ${TEST_SUITE_WEBPACK_ARG}

# Run tests
# shellcheck disable=SC2086
SKETCH_TARGET_PATH="$(mdfind kMDItemCFBundleIdentifier == ${SKETCH_VARIANT_BUNDLE_ID} | sort --version-sort --reverse | head -n 1)"
echo "• Running tests in '${SKETCH_TARGET_PATH}'"

python3 run_tests.py \
-p "./build/SketchIntegrationTests-${TEST_RUN_ID}.sketchplugin" \
-o "./build/${TEST_RUN_ID}_test_results.txt" \
-s "${SKETCH_TARGET_PATH}"

# Tear down test environment
tear_down

# Clean up test artifacts
rm -rf "./build/SketchIntegrationTests-${TEST_RUN_ID}.sketchplugin"
rm -rf "./build/${TEST_RUN_ID}_test_results.txt"
Loading