Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions .changeset/fix-capacitor-batch-operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/capacitor': patch
---

Fix Capacitor batch operations so they do not start a nested native transaction when executed inside PowerSync's write transaction wrapper.
70 changes: 70 additions & 0 deletions .github/actions/setup-android-emulator/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Setup Android Emulator
description: Configure KVM, Java, Gradle, and a cached Android emulator snapshot.
inputs:
avd-name:
description: Name of the Android Virtual Device to create or reuse.
required: true
cache-key:
description: Cache key for the Android Virtual Device files.
required: true
api-level:
description: Android API level for the emulator.
required: false
default: '31'
target:
description: Android system image target.
required: false
default: google_apis
arch:
description: Android system image architecture.
required: false
default: x86_64
java-version:
description: JDK version to install for Android builds.
required: false
default: '17'
runs:
using: composite
steps:
- name: Enable KVM group perms
shell: bash
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: AVD Cache
uses: actions/cache@v3
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: ${{ inputs.cache-key }}

- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: ${{ inputs.java-version }}
distribution: adopt
cache: gradle

- name: Initialize Android Folder
shell: bash
run: mkdir -p ~/.android/avd

- name: Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2.28.0
with:
api-level: ${{ inputs.api-level }}
force-avd-creation: false
target: ${{ inputs.target }}
arch: ${{ inputs.arch }}
disable-animations: false
avd-name: ${{ inputs.avd-name }}
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
script: echo "Generated AVD snapshot for caching."
131 changes: 86 additions & 45 deletions .github/workflows/test-simulators.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ name: Test Simulators/Emulators
on:
pull_request: # triggered for any PR updates (including new pushes to PR branch)

permissions:
contents: read

jobs:
check-changes:
name: Check for relevant changes
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.check.outputs.should_run }}
react_native_simulator_should_run: ${{ steps.check.outputs.react_native_simulator_should_run }}
capacitor_should_run: ${{ steps.check.outputs.capacitor_should_run }}
steps:
- uses: actions/checkout@v6
with:
Expand All @@ -18,15 +22,21 @@ jobs:
run: |
git fetch origin ${{ github.base_ref }}
if git diff --quiet origin/${{ github.base_ref }} -- packages/common packages/powersync-op-sqlite tools/powersynctests; then
echo "should_run=false" >> $GITHUB_OUTPUT
echo "react_native_simulator_should_run=false" >> $GITHUB_OUTPUT
else
echo "react_native_simulator_should_run=true" >> $GITHUB_OUTPUT
fi

if git diff --quiet origin/${{ github.base_ref }} -- packages/capacitor pnpm-lock.yaml .github/workflows/test-simulators.yaml; then
echo "capacitor_should_run=false" >> $GITHUB_OUTPUT
else
echo "should_run=true" >> $GITHUB_OUTPUT
echo "capacitor_should_run=true" >> $GITHUB_OUTPUT
fi

test-android:
name: Test Android
needs: check-changes
if: ${{ needs.check-changes.outputs.should_run == 'true' }}
if: ${{ needs.check-changes.outputs.react_native_simulator_should_run == 'true' }}
runs-on: ubuntu-xl
timeout-minutes: 30
env:
Expand All @@ -36,30 +46,11 @@ jobs:
with:
persist-credentials: false

- name: Enable KVM group perms
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: AVD Cache
uses: actions/cache@v3
id: avd-cache
- name: Setup Android emulator
uses: ./.github/actions/setup-android-emulator
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-31

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: 17
distribution: 'adopt'
cache: 'gradle'
avd-name: ${{ env.AVD_NAME }}
cache-key: avd-31

- name: Enable Corepack
run: corepack enable
Expand All @@ -80,22 +71,6 @@ jobs:
run: |
pnpx detox clean-framework-cache && pnpx detox build-framework-cache

- name: Initialize Android Folder
run: mkdir -p ~/.android/avd

- name: create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2.28.0
with:
api-level: 31
force-avd-creation: false
target: google_apis
arch: x86_64
disable-animations: false
avd-name: $AVD_NAME
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
script: echo "Generated AVD snapshot for caching."

- name: Android Emulator Build
working-directory: ./tools/powersynctests
run: pnpx detox build --configuration android.emu.release
Expand All @@ -106,18 +81,84 @@ jobs:
api-level: 31
target: google_apis
arch: x86_64
avd-name: $AVD_NAME
avd-name: ${{ env.AVD_NAME }}
script: cd tools/powersynctests && pnpx detox test --configuration android.emu.release --headless
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true

test-capacitor-android:
name: Test Capacitor Android
needs: check-changes
if: ${{ needs.check-changes.outputs.capacitor_should_run == 'true' }}
runs-on: ubuntu-xl
timeout-minutes: 30
env:
AVD_NAME: capacitor-avd-x86_64-35
TEST_PLATFORM: android
TEST_TARGET: emulator-5554
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false

- name: Setup Android emulator
uses: ./.github/actions/setup-android-emulator
with:
avd-name: ${{ env.AVD_NAME }}
cache-key: capacitor-avd-35
api-level: '35'
java-version: '21'

- name: Enable Corepack
run: corepack enable

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: pnpm

- name: Install dependencies
run: pnpm install

- name: Build
run: pnpm build:packages

- name: Install Capacitor example dependencies
working-directory: ./packages/capacitor/example-app
run: pnpm install

- name: Sync and build Capacitor Android app
working-directory: ./packages/capacitor/example-app
# Prebuild the native app so the later browser-test action can start quickly.
# This dummy Vitest server URL is only used for the prebuild; the test run
# updates Capacitor with the actual Vitest URL before launching the app.
env:
CAPACITOR_VITEST_SERVER_URL: http://10.0.2.2
run: |
pnpm exec cap sync android
cd android
./gradlew assembleDebug

- name: Run Capacitor Android browser tests
uses: reactivecircus/android-emulator-runner@v2.28.0
with:
api-level: 35
target: google_apis
arch: x86_64
avd-name: ${{ env.AVD_NAME }}
script: pnpm --dir packages/capacitor exec vitest run --config vitest.config.ts
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true

test-ios:
name: Test iOS
needs: check-changes
# TODO: Re-enable iOS tests. They have been disabled because they are failing extremely frequently without
# any apparent cause. In particular, it seems like even starting the simulator times out most of the time.
if: ${{ false && needs.check-changes.outputs.should_run == 'true' }}
if: ${{ false && needs.check-changes.outputs.react_native_simulator_should_run == 'true' }}
runs-on: macOS-15
timeout-minutes: 30

Expand Down
41 changes: 41 additions & 0 deletions demos/example-capacitor/ios/App/CapApp-SPM/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 67 additions & 0 deletions packages/capacitor/DEVELOP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Developing the Capacitor SDK

## Native browser integration tests

The Capacitor package uses Vitest browser mode with a custom provider. Vitest starts a browser test server, then the provider runs the example Capacitor app and points the app at that server.

Build the workspace before running these tests so the Capacitor package can resolve generated workspace package outputs:

```sh
pnpm install
pnpm build:packages
cd packages/capacitor/example-app
pnpm install
cd ..
```

The test provider reads these environment variables:

- `TEST_PLATFORM`: Native platform to run. Use `ios` or `android`.
- `TEST_TARGET`: Simulator/emulator target id passed to `cap run --target`.
- `TEST_SERVER_HOST`: Hostname the native app should use to reach the Vitest server. Android defaults to `10.0.2.2`; iOS uses the Vitest URL host as-is.

### iOS

List available iOS simulator targets:

```sh
cd packages/capacitor/example-app
pnpm exec cap run ios --list
```

Run the integration tests on a simulator:

```sh
cd packages/capacitor
TEST_PLATFORM=ios \
TEST_TARGET=<ios-simulator-id> \
pnpm exec vitest run --config vitest.config.ts
```

### Android

Create the Android example app platform if it is not present yet:

```sh
cd packages/capacitor/example-app
pnpm exec cap add android
```

List available Android emulator/device targets:

```sh
adb devices
```

For the default Android emulator, the target is usually `emulator-5554`.

Run the integration tests on Android:

```sh
cd packages/capacitor
TEST_PLATFORM=android \
TEST_TARGET=emulator-5554 \
pnpm exec vitest run --config vitest.config.ts
```

Android defaults `TEST_SERVER_HOST` to `10.0.2.2`, which lets the emulator reach the host machine without `adb reverse`. The Vitest config also binds the test server to `0.0.0.0` for this reason.
Loading
Loading