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
4 changes: 3 additions & 1 deletion .forgejo/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ jobs:
run: cargo build

- name: Run tests
run: cargo test
run: |
cargo test
node --test tests/*.test.js

- name: Verify package contents
run: ./scripts/verify-package.sh
4 changes: 3 additions & 1 deletion .forgejo/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ jobs:
run: cargo build --release

- name: Run tests
run: cargo test
run: |
cargo test
node --test tests/*.test.js

create-release:
name: Create Release
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ jobs:
run: cargo build

- name: Run tests
run: cargo test
run: |
cargo test
node --test tests/*.test.js
Comment on lines +50 to +52
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate release validation on the new frontend test suite

These lines add node --test to pull-request CI, but the release paths still stop at cargo test in .github/workflows/release.yml:50-51, .forgejo/workflows/release.yml:31-32, and the documented make pre-release target at Makefile:205-206. A regression in the shipped JavaScript can therefore still pass the actual release gate and be published from a tag without ever running the new suite, which defeats the coverage in the most important path.

Useful? React with 👍 / 👎.


- name: Verify package contents
run: ./scripts/verify-package.sh
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ jobs:
run: cargo build --release

- name: Run tests
run: cargo test
run: |
cargo test
node --test tests/*.test.js

create-release:
name: Create GitHub Release
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ include_dir = "0.7"

[dev-dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
tower = "0.5"
tower = { version = "0.5", features = ["util"] }
20 changes: 17 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ VERSIONED_CSS := static/sf/sf.$(VERSION).css
VERSIONED_JS := static/sf/sf.$(VERSION).js

# ============== Phony Targets ==============
.PHONY: banner help assets build build-release test test-quick test-doc test-unit test-one \
.PHONY: banner help assets build build-release test test-quick test-doc test-unit test-frontend test-one \
lint fmt fmt-check clippy ci-local pre-release version package-verify \
bump-patch bump-minor bump-major bump-dry demo-serve \
publish-dry publish clean watch
Expand Down Expand Up @@ -84,6 +84,7 @@ test: banner
@printf "$(CYAN)$(BOLD)╚══════════════════════════════════════╝$(RESET)\n\n"
@printf "$(ARROW) $(BOLD)Running all tests...$(RESET)\n"
@cargo test && \
node --test tests/*.test.js && \
printf "\n$(GREEN)$(CHECK) All tests passed$(RESET)\n\n" || \
(printf "\n$(RED)$(CROSS) Tests failed$(RESET)\n\n" && exit 1)

Expand All @@ -99,6 +100,10 @@ test-quick: banner
@cargo test --lib --quiet && \
printf "$(GREEN)$(CHECK) Unit tests passed$(RESET)\n\n" || \
(printf "$(RED)$(CROSS) Unit tests failed$(RESET)\n\n" && exit 1)
@printf "$(PROGRESS) Running frontend tests...\n"
@node --test tests/*.test.js && \
printf "$(GREEN)$(CHECK) Frontend tests passed$(RESET)\n\n" || \
(printf "$(RED)$(CROSS) Frontend tests failed$(RESET)\n\n" && exit 1)

test-doc:
@printf "$(PROGRESS) Running doctests...\n"
Expand All @@ -112,6 +117,12 @@ test-unit:
printf "$(GREEN)$(CHECK) Unit tests passed$(RESET)\n" || \
(printf "$(RED)$(CROSS) Unit tests failed$(RESET)\n" && exit 1)

test-frontend:
@printf "$(PROGRESS) Running frontend tests...\n"
@node --test tests/*.test.js && \
printf "$(GREEN)$(CHECK) Frontend tests passed$(RESET)\n" || \
(printf "$(RED)$(CROSS) Frontend tests failed$(RESET)\n" && exit 1)

test-one:
@printf "$(PROGRESS) Running test: $(YELLOW)$(TEST)$(RESET)\n"
@RUST_LOG=info cargo test $(TEST) -- --nocapture
Expand Down Expand Up @@ -155,8 +166,10 @@ ci-local: banner
@$(MAKE) clippy --no-print-directory
@printf "$(PROGRESS) Step 5/6: Doctests...\n"
@cargo test --doc --quiet && printf "$(GREEN)$(CHECK) Doctests passed$(RESET)\n"
@printf "$(PROGRESS) Step 6/6: Unit tests...\n"
@printf "$(PROGRESS) Step 6/7: Unit tests...\n"
@cargo test --lib --quiet && printf "$(GREEN)$(CHECK) Unit tests passed$(RESET)\n"
@printf "$(PROGRESS) Step 7/7: Frontend tests...\n"
@node --test tests/*.test.js && printf "$(GREEN)$(CHECK) Frontend tests passed$(RESET)\n"
@printf "\n$(GREEN)$(BOLD)╔══════════════════════════════════════════════════════════╗$(RESET)\n"
@printf "$(GREEN)$(BOLD)║ $(CHECK) CI SIMULATION PASSED ║$(RESET)\n"
@printf "$(GREEN)$(BOLD)╚══════════════════════════════════════════════════════════╝$(RESET)\n\n"
Expand Down Expand Up @@ -196,7 +209,7 @@ pre-release: banner
@$(MAKE) fmt-check --no-print-directory
@$(MAKE) clippy --no-print-directory
@printf "$(PROGRESS) Running full test suite...\n"
@cargo test --quiet && printf "$(GREEN)$(CHECK) All tests passed$(RESET)\n"
@cargo test --quiet && node --test tests/*.test.js && printf "$(GREEN)$(CHECK) All tests passed$(RESET)\n"
@printf "$(PROGRESS) Dry-run publish...\n"
@cargo publish --dry-run 2>&1 | tail -1
@printf "$(PROGRESS) Verifying packaged contents...\n"
Expand Down Expand Up @@ -273,6 +286,7 @@ help: banner
@/bin/echo -e " $(GREEN)make test-quick$(RESET) - Run doctests + unit tests (fast)"
@/bin/echo -e " $(GREEN)make test-doc$(RESET) - Run doctests only"
@/bin/echo -e " $(GREEN)make test-unit$(RESET) - Run unit tests only"
@/bin/echo -e " $(GREEN)make test-frontend$(RESET) - Run frontend Node tests"
@/bin/echo -e " $(GREEN)make test-one TEST=name$(RESET) - Run specific test with output"
@/bin/echo -e ""
@/bin/echo -e "$(CYAN)$(BOLD)Lint & Format:$(RESET)"
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ Every backend element has a corresponding UI element. The library grows
alongside the solver. When you scaffold a new SolverForge project with
`solverforge new`, it's already wired in.

## Testing

Repository coverage now includes the embedded Rust asset routes plus Node-based
frontend tests for backend adapters, solver lifecycle transitions, and core
component rendering. Use `make test` for the full suite, `make test-quick` for
Rust doctests and unit tests plus frontend coverage, or `make test-frontend`
when you only want the JavaScript suite.

## Quick Start

```html
Expand Down
89 changes: 89 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,93 @@ mod tests {

assert_eq!(missing_resp.status(), StatusCode::NOT_FOUND);
}

#[tokio::test]
async fn serves_top_level_assets_with_short_cache_and_expected_mime() {
let response = routes()
.oneshot(
Request::builder()
.uri("/sf/sf.css")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();

assert_eq!(response.status(), StatusCode::OK);
assert_eq!(
response.headers().get(header::CONTENT_TYPE).unwrap(),
"text/css; charset=utf-8"
);
assert_eq!(
response.headers().get(header::CACHE_CONTROL).unwrap(),
"public, max-age=3600"
);

let body = to_bytes(response.into_body(), usize::MAX).await.unwrap();
let css = String::from_utf8(body.to_vec()).unwrap();
assert!(css.contains("--sf-emerald-50"));
assert!(css.contains(".sf-gantt-split"));
}

#[tokio::test]
async fn serves_immutable_assets_with_long_cache_and_expected_mime() {
let image = routes()
.oneshot(
Request::builder()
.method(Method::GET)
.uri("/sf/img/ouroboros.svg")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();

assert_eq!(image.status(), StatusCode::OK);
assert_eq!(
image.headers().get(header::CONTENT_TYPE).unwrap(),
"image/svg+xml"
);
assert_eq!(
image.headers().get(header::CACHE_CONTROL).unwrap(),
"public, max-age=31536000, immutable"
);

let vendor = routes()
.oneshot(
Request::builder()
.method(Method::GET)
.uri("/sf/vendor/frappe-gantt/frappe-gantt.min.js")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();

assert_eq!(vendor.status(), StatusCode::OK);
assert_eq!(
vendor.headers().get(header::CONTENT_TYPE).unwrap(),
"application/javascript; charset=utf-8"
);
assert_eq!(
vendor.headers().get(header::CACHE_CONTROL).unwrap(),
"public, max-age=31536000, immutable"
);
}

#[tokio::test]
async fn returns_not_found_for_missing_assets() {
let response = routes()
.oneshot(
Request::builder()
.method(Method::GET)
.uri("/sf/does-not-exist.js")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();

assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
}
Loading
Loading