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
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: ci

on:
push:
branches: [main, develop]
pull_request:
branches: [main]
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Initialize public plugin submodules
run: git submodule update --init woo prestashop magento

- uses: pnpm/action-setup@v4
with:
version: 9

- uses: actions/setup-node@v4
with:
node-version: "22"
cache: pnpm
cache-dependency-path: woo/pnpm-lock.yaml

- name: Run automated plugin test suite
run: ./scripts/run-plugin-tests.sh
128 changes: 128 additions & 0 deletions DEV-ENV.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Plugin development environments

Documents what contributors need to run and test lomi. e-commerce plugins locally. Parent epic: [lomi. #45](https://github.com/lomiafrica/lomi./issues/45) · issue **#44**.

No production store is required — use **lomi. sandbox (test mode)** and a local or staging shop.

## Access checklist

| Item | Who provides | Notes |
| --- | --- | --- |
| GitHub org access | lomi. team | Required for private submodules: `shopify`, `bubble`, `odoo` |
| lomi. sandbox org | You or team | [dashboard.lomi.africa](https://dashboard.lomi.africa) — **test** secret key + webhook signing secret |
| HTTPS tunnel | You | Cloudflare Tunnel (or ngrok) so lomi. can POST webhooks to your machine |
| Submodule clone | You | `git clone --recursive` or `git submodule update --init --recursive` |

Never commit API keys, webhook secrets, or tunnel tokens to git.

---

## WooCommerce (Docker + Cloudflare Tunnel)

Recommended setup used for manual E2E and plugin UX work.

### Stack

- **Docker Compose**: WordPress + MySQL 8 ([`dev/woocommerce/docker-compose.yml`](./dev/woocommerce/docker-compose.yml))
- **Plugin**: bind-mount `woo/` submodule → `wp-content/plugins/woo-lomi`
- **Store URL (local)**: http://localhost:8080
- **Public HTTPS**: Cloudflare Tunnel → same WordPress instance
- **lomi.**: sandbox API (`https://sandbox.api.lomi.africa`), test mode ON in Woo settings

### Start

```bash
cd dev/woocommerce
docker compose up -d
```

1. Complete WordPress install in the browser.
2. Install and activate **WooCommerce** (9.6+).
3. Activate **lomi. for WooCommerce**.
4. In WooCommerce → Settings → Payments → **lomi.**: enable gateway, **test mode**, paste test secret key + test webhook secret.
5. Copy the **webhook URL** from Woo settings into dashboard → **Developers → Webhooks** (events: `PAYMENT_SUCCEEDED`, `REFUND_COMPLETED` recommended).

### Cloudflare Tunnel

Expose port **8080** so webhooks reach WordPress:

```bash
# Quick tunnel (ephemeral URL)
cloudflared tunnel --url http://localhost:8080
```

Or use a named tunnel + `config.yml` if you have a fixed hostname.

**Important:** In WordPress **Settings → General**, set **Site Address (URL)** to your public tunnel URL when testing checkout return URLs and webhooks. If the site URL stays `http://localhost:8080`, redirects after payment may break for external services.

### Plugin from zip instead of bind-mount

```bash
cd woo
pnpm install
pnpm run release
# Upload dist/woo-lomi.zip via Plugins → Add New → Upload
```

### Manual E2E

Follow [E2E.md](./E2E.md) → WooCommerce section after the environment is up.

### Automated checks (no Docker required)

```bash
./scripts/verify-lomi-plugins.sh
```

CI runs the same script on pull requests.

---

## PrestaShop

- Module folder: `prestashop/lomi/` — zip **`lomi/`** only (root of archive = `lomi/`).
- Local: Docker or native PrestaShop 1.7+ / 8.x, currency EUR/USD/XOF, HTTPS for webhooks.
- See [prestashop/lomi/README.md](prestashop/lomi/README.md) and [E2E.md](./E2E.md).

---

## Magento 2

- Package: `lomi/magento2-payments` — **not on Packagist**; use Composer VCS or copy to `app/code/Lomi/Payments/`.
- Docker dev stack: [`magento/dev`](magento/dev) (see submodule README).
- Webhooks need a public HTTPS URL (Cloudflare Tunnel or ngrok).
- See [E2E.md](./E2E.md).

---

## Shopify

- Custom install app — no zip. Enable in dashboard → **Settings → Payment channels → Integrations**.
- Requires org access to private `shopify` submodule.
- See [docs: Shopify](https://docs.lomi.africa/build/ecommerce-extensions/shopify).

---

## Bubble

- Plugin project in `bubble` submodule (private repo).
- CI: JSON validation + `scripts/smoke-test.mjs` on release workflow.
- See [E2E.md](./E2E.md) and submodule README.

---

## What to request from the team

If you are blocked, ask for:

1. **Sandbox** lomi. org with test API key and webhook secret confirmed.
2. **GitHub** access to private plugin repos you need (Shopify, Bubble, Odoo).
3. **Shared staging** shop (optional) — not required if Docker + tunnel works for Woo.

---

## Related docs

- [E2E.md](./E2E.md) — manual smoke matrix per platform
- [docs.lomi.africa — E‑commerce](https://docs.lomi.africa/build/ecommerce-extensions)
- [verify-lomi-plugins.sh](./scripts/verify-lomi-plugins.sh) — static contract gate
21 changes: 14 additions & 7 deletions E2E.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,26 @@ Manual checklist per platform. Run in **test mode** first, then repeat critical
| Test/live toggle | API base + webhook secret switch together |
| Abandon | Back from hosted checkout restores cart / pending order |

Automated static gate: `./scripts/verify-lomi-plugins.sh`
Automated suite: `./scripts/run-plugin-tests.sh` (static parity + webhook contract + Woo zip). Static-only: `./scripts/run-plugin-tests.sh --fast`

---

## WooCommerce

**Environment:** wp-env, staging store, or local WordPress + Woo.
**Environment:** Docker Compose ([`dev/woocommerce`](./dev/woocommerce)) + **Cloudflare Tunnel** for HTTPS webhooks, or shared staging. See [DEV-ENV.md](./DEV-ENV.md).

1. Configure test API key + test webhook secret; enable test mode.
2. Place order → redirect to lomi. checkout → pay (sandbox).
3. Confirm order `processing`/`completed` and webhook note.
4. Toggle live keys (staging only if available); confirm `api.lomi.africa` used.
5. Start checkout, use browser Back → cart restored (abandon JS).
```bash
cd dev/woocommerce && docker compose up -d
# cloudflared tunnel --url http://localhost:8080
```

1. Install WooCommerce; activate `woo-lomi` (bind-mounted from `woo/` submodule).
2. Configure test API key + test webhook secret; enable test mode.
3. Set WordPress site URL to tunnel hostname when testing checkout return + webhooks.
4. Place order → redirect to lomi. checkout → pay (sandbox).
5. Confirm order `processing`/`completed` and webhook note.
6. Toggle live keys (staging only if available); confirm `api.lomi.africa` used.
7. Start checkout, use browser Back → cart restored (abandon JS).

---

Expand Down
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,22 @@ If a submodule fails with "repository not found", that platform repo is private

## End-to-end tests and scripts

- **[DEV-ENV.md](./DEV-ENV.md)**: Local dev setup (Docker, Cloudflare Tunnel, sandbox keys) — **start here for new contributors**.
- **[E2E.md](./E2E.md)**: Manual smoke matrix per platform (checkout, webhooks, abandon flows, release tags).
- **[scripts/verify-lomi-plugins.sh](./scripts/verify-lomi-plugins.sh)**: Static compliance gate (API contract, `integration_source`, XOF amounts, legacy brand checks, webhook patterns).
- **[scripts/run-plugin-tests.sh](./scripts/run-plugin-tests.sh)**: **Automated CI suite** — static parity, webhook contract, Bubble JSON, Woo build + release zip.
- **[scripts/verify-lomi-plugins.sh](./scripts/verify-lomi-plugins.sh)**: Static compliance gate (also run as step 1 of `run-plugin-tests.sh`).
- **[scripts/scan_broken_images.py](./scripts/scan_broken_images.py)**: Scans Magento, PrestaShop, and Woo trees for broken image path references.

Run the static gate from the repository root:
Run the full automated suite from the repository root (requires Node 22+, pnpm 9+, `unzip`):

```bash
./scripts/verify-lomi-plugins.sh
./scripts/run-plugin-tests.sh
```

Static checks only (no Woo `pnpm build`):

```bash
./scripts/run-plugin-tests.sh --fast
```

## Contributing
Expand All @@ -63,7 +71,7 @@ Pull requests and issue reports are welcome.

- **Platform plugin changes**: work inside the relevant submodule, push to that submodule's repo, then update the submodule pointer here if needed.
- **Reference app or shared script changes**: edit files directly in this repository (`direct-charge-integration-reference`, `payment-integration-reference`, `payment-integration-sdk-reference`, `scripts/`, `E2E.md`).
- Run `./scripts/verify-lomi-plugins.sh` before opening a PR.
- Run `./scripts/run-plugin-tests.sh` before opening a PR (`--fast` if Woo assets are unchanged).

## License

Expand Down
23 changes: 23 additions & 0 deletions dev/woocommerce/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# WooCommerce local dev (Docker)

Quick start for plugin development. Full checklist: [DEV-ENV.md](../../DEV-ENV.md).

```bash
cd dev/woocommerce
docker compose up -d
```

1. Open http://localhost:8080 and finish WordPress setup.
2. Install **WooCommerce** (Plugins → Add New, or WP-CLI below).
3. Activate **lomi. for WooCommerce** (`woo-lomi`).
4. Expose HTTPS with **Cloudflare Tunnel** (see DEV-ENV.md).
5. Configure sandbox keys in Woo + [dashboard.lomi.africa](https://dashboard.lomi.africa).

### WP-CLI (optional)

```bash
docker compose exec wordpress bash -c \
'curl -sO https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && chmod +x wp-cli.phar && mv wp-cli.phar /usr/local/bin/wp'

docker compose exec wordpress wp plugin install woocommerce --activate --allow-root
```
34 changes: 34 additions & 0 deletions dev/woocommerce/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Local WooCommerce + lomi. plugin (bind-mount from submodule).
# From this directory: docker compose up -d
# Store: http://localhost:8080

services:
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
MYSQL_ROOT_PASSWORD: root
volumes:
- db_data:/var/lib/mysql

wordpress:
image: wordpress:latest
depends_on:
- db
ports:
- "8080:80"
restart: unless-stopped
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
# Repo layout: dev/woocommerce → ../../woo
- ../../woo:/var/www/html/wp-content/plugins/woo-lomi

volumes:
db_data:
95 changes: 95 additions & 0 deletions scripts/run-plugin-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
# Automated plugin test suite (issue #39). Runs static parity checks plus smoke tests.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGINS_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
FAST=0
SKIP_WOO=0

usage() {
cat <<'EOF'
Usage:
./scripts/run-plugin-tests.sh [--fast] [--skip-woo]

Runs:
1) verify-lomi-plugins.sh — static API contract, branding, legacy brand scan
2) test_webhook_signature.mjs — HMAC-SHA256 webhook contract
3) test_bubble_json.mjs — Bubble plugin JSON parse smoke (skipped if submodule empty)
4) Woo build + release zip validation (unless --fast or --skip-woo)

Options:
--fast Static checks only (no Woo pnpm build / zip)
--skip-woo Skip Woo build and zip validation
EOF
}

log() {
printf "\n[%s] %s\n" "$(date +'%H:%M:%S')" "$1"
}

while [[ $# -gt 0 ]]; do
case "$1" in
--fast)
FAST=1
shift
;;
--skip-woo)
SKIP_WOO=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1"
usage
exit 1
;;
esac
done

if ! command -v node >/dev/null 2>&1; then
echo "FAIL: node is required"
exit 1
fi

log "1/4 Static plugin parity (verify-lomi-plugins.sh)"
bash "${SCRIPT_DIR}/verify-lomi-plugins.sh"

log "2/4 Webhook signature contract"
node "${SCRIPT_DIR}/test_webhook_signature.mjs"

log "3/4 Bubble JSON smoke"
node "${SCRIPT_DIR}/test_bubble_json.mjs"

if [[ "${SKIP_WOO}" == "1" || "${FAST}" == "1" ]]; then
log "4/4 Woo release zip — SKIPPED"
else
log "4/4 Woo build + release zip"
WOO_DIR="${PLUGINS_DIR}/woo"
if [[ ! -f "${WOO_DIR}/woo-lomi.php" ]]; then
echo "FAIL: woo submodule not initialized (${WOO_DIR})"
exit 1
fi
if [[ ! -f "${WOO_DIR}/pnpm-lock.yaml" ]]; then
echo "FAIL: woo/pnpm-lock.yaml missing"
exit 1
fi
if ! command -v pnpm >/dev/null 2>&1; then
echo "FAIL: pnpm is required for Woo build tests"
exit 1
fi
(
cd "${WOO_DIR}"
pnpm install --frozen-lockfile
pnpm run build
if grep -q '"i18n"' package.json 2>/dev/null; then
pnpm run i18n
fi
)
RUN_RELEASE=1 WOO_DIR="${WOO_DIR}" bash "${SCRIPT_DIR}/test_woo_release_zip.sh"
fi

log "All automated plugin tests passed."
Loading
Loading