Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
b79e4c1
chore: updating project description
giulong Oct 10, 2025
090a6fb
docs: updating README
giulong Oct 10, 2025
227f889
build: all tests run with a default timeout of 5 minutes to avoid end…
giulong Oct 10, 2025
af8a953
docs: adding json schema video in corresponding docs section
giulong Oct 10, 2025
814aa8d
docs: removing gradle dependency snippet, leaving maven, and suggesti…
giulong Oct 11, 2025
e283c7f
build(deps): bump org.jacoco:jacoco-maven-plugin from 0.8.13 to 0.8.14
dependabot[bot] Oct 13, 2025
2b23c2b
build(deps): bump net.datafaker:datafaker from 2.5.1 to 2.5.2
dependabot[bot] Oct 13, 2025
33ca8cc
build(deps): bump com.puppycrawl.tools:checkstyle from 11.1.0 to 12.0.1
dependabot[bot] Oct 13, 2025
d9d51fd
Merge pull request #482 from giulong/dependabot/maven/develop/com.pup…
giulong Oct 13, 2025
e92710e
Merge pull request #480 from giulong/dependabot/maven/develop/org.jac…
giulong Oct 13, 2025
7319e51
Merge pull request #481 from giulong/dependabot/maven/develop/net.dat…
giulong Oct 13, 2025
6a5c8c1
build(deps): bump selenium.version from 4.36.0 to 4.37.0
dependabot[bot] Oct 20, 2025
c7906e9
build(deps): bump com.puppycrawl.tools:checkstyle from 12.0.1 to 12.1.0
dependabot[bot] Oct 20, 2025
ccf17a2
build(deps): bump ch.qos.logback:logback-classic from 1.5.19 to 1.5.20
dependabot[bot] Oct 20, 2025
3ae8d29
Merge pull request #484 from giulong/dependabot/maven/develop/com.pup…
giulong Oct 21, 2025
ee7b174
Merge pull request #485 from giulong/dependabot/maven/develop/ch.qos.…
giulong Oct 21, 2025
ff43155
fix(bidi): changing how bidi activation is checked
giulong Oct 21, 2025
36e313c
Merge pull request #483 from giulong/dependabot/maven/develop/seleniu…
giulong Oct 21, 2025
e2c2011
chore: introducing editorconfig with yaml and java rules
giulong Oct 22, 2025
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
36 changes: 36 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4
charset = utf-8

[*.java]
ij_visual_guides = 180
ij_java_align_multiline_throws_list = true
ij_java_align_multiline_annotation_parameters = true
ij_java_annotation_parameter_wrap = off
ij_java_blank_lines_after_imports = 1
ij_java_blank_lines_before_imports = 1
ij_java_class_count_to_use_import_on_demand = 5
ij_java_names_count_to_use_import_on_demand = 5
ij_java_imports_layout = static java.**,static javax.**,$*,|,java.**,javax.**,*
ij_java_insert_inner_class_imports = true
ij_java_layout_static_imports_separately = false
ij_java_method_call_chain_wrap = off
ij_java_throws_list_wrap = off
ij_java_block_comment_at_first_column = false
ij_java_line_comment_at_first_column = false
ij_java_line_comment_add_space = true

[{*.yml,*.yaml}]
indent_size = 2
ij_continuation_indent_size = 2
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
ij_any_block_comment_at_first_column = false
ij_java_line_comment_at_first_column = false
ij_java_line_comment_add_space = true
89 changes: 53 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,12 @@

Spectrum is an **e2e test automation framework** that leverages **JUnit 6** and **Selenium 4** to provide these features automatically:

* **Driver** management
* **Auto-waiting** before interacting with elements, to **highly reduce flakiness**
* **Html report** generation with the **execution video**
* **Coverage report** generation by reading a **testbook**
* **Driver** management with **auto-waiting**, to **highly reduce flakiness**
* Generation of a **html report** with the **execution video**, **coverage** and **several additional reports**. All **fully customisable**
* **Mail/Slack notifications** with reports as attachments
* It is fully configurable via a **declarative yaml file**
* It provides **out-of-the-box defaults** to let you run tests with no additional configuration
* It supports **browsers automation** via Selenium
* It supports **mobile and desktop applications automation** via Appium
* It is fully configurable via a **declarative yaml file**, providing **out-of-the-box defaults** to let you run tests with no additional configuration
* It supports **browsers automation** via Selenium and **mobile and desktop automation** via Appium
* It supports **WebDriver BiDi** protocol
* It generates **several additional reports** that are **fully customisable**

Spectrum manages all the boilerplate code, allowing you to focus on test logic:
you just need to write a JUnit test using the native Selenium API as you would do in a vanilla Selenium test,
Expand All @@ -73,37 +68,11 @@ https://github.com/giulong/spectrum/assets/27963644/fecee8f5-f6dc-4b47-81a3-514e
```

2. Run the `LoginFormIT` demo test.
3. Check the report generated under `target/spectrum/reports`.
3. Check the generated report, which opens automatically in your browser.

> ⚠️ Tests run on Chrome by default. As shown in the video above, you can change this with:<br/>
> `-Dspectrum.driver=firefox`, `-Dspectrum.driver=edge` or `-Dspectrum.driver=safari`

If you like Spectrum, please consider giving it a GitHub Star ⭐

# Usage

If you'd rather add Spectrum manually to your project, you just need to add its dependency:

## Maven

```xml

<dependency>
<groupId>io.github.giulong</groupId>
<artifactId>spectrum</artifactId>
<version>1.26.1</version>
<scope>test</scope>
</dependency>
```

## Gradle

```gradle
dependencies {
testImplementation group: 'io.github.giulong', name: 'spectrum', version: '1.26.1'
}
```

Here's an overview of the project created by the archetype, along with the generated report and video:<br/><br/>
<img style="width: 49%; vertical-align: top;" src="src/main/resources/images/login-form-it.png" alt="login-form"/>
&nbsp;<img style="width: 49%; vertical-align: top;" src="src/main/resources/images/login-form-it-extent-report.png" alt="report"/>
Expand All @@ -114,6 +83,54 @@ You can also configure Spectrum to produce additional reports, such as summary a
<img style="width: 49%; vertical-align: top;" src="src/main/resources/images/html-summary.png" alt="summary"/>
&nbsp;<img style="width: 49%; vertical-align: top;" src="src/main/resources/images/html-testbook.png" alt="html testbook"/>

If you like Spectrum, please consider giving it a GitHub Star ⭐

# Usage

To start without the archetype, it's as simple as following these steps:

1. Add the Spectrum dependency to your project, you can find the snippet for every build tool [here](https://central.sonatype.com/artifact/io.github.giulong/spectrum).

```xml
<dependency>
<groupId>io.github.giulong</groupId>
<artifactId>spectrum</artifactId>
<version>1.26.1</version>
<scope>test</scope>
</dependency>
```

2. Create the `HelloWorldIT` test class extending `SpectrumTest`:

```java
import io.github.giulong.spectrum.SpectrumTest;
import org.junit.jupiter.api.Test;

public class HelloWorldIT extends SpectrumTest<Void> {

@Test
public void dummyTest() {
driver.get(configuration.getApplication().getBaseUrl());
}
}
```

3. create a basic `src/test/resources/configuration.yaml`:

```yaml
application:
baseUrl: https://the-internet.herokuapp.com/ # Change this with your app's landing page

video: # video of the execution attached to the html report (will be empty since the test is doing nothing)
frames:
- autoBefore

extent:
openAtEnd: true # the html report will open automatically in your browser after the execution
```

4. Run the test!

# Contributing

Contributions to Spectrum are welcome! Please check out the [CONTRIBUTING.md](CONTRIBUTING.md)
Expand Down
46 changes: 27 additions & 19 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ and **mobile and desktop applications** via [Appium](http://appium.io/docs/en/la

## Spectrum Archetype

You should leverage the latest published version of the [Spectrum Archetype](https://mvnrepository.com/artifact/io.github.giulong/spectrum-archetype){:target="_blank"} to create a
new project either via your IDE or by running this from command line:
You should leverage the latest published version of the [Spectrum Archetype](https://central.sonatype.com/artifact/io.github.giulong/spectrum-archetype){:target="_blank"}
to create a new project either via your IDE or by running this from command line:

{% include copyCode.html %}

Expand All @@ -48,10 +48,11 @@ mvn archetype:generate -DarchetypeGroupId=io.github.giulong -DarchetypeArtifactI
> official [archetype:generate docs](https://maven.apache.org/archetype/maven-archetype-plugin/generate-mojo.html){:target="_blank"}.

The project created contains a demo test you can immediately run.
If you don't want to leverage the archetype, you can manually add the [Spectrum dependency](https://mvnrepository.com/artifact/io.github.giulong/spectrum){:target="_blank"} to your
project:

## Maven
## Manual Configuration

If you don't want to leverage the archetype, you can manually add the Spectrum dependency to your project.
[Here](https://central.sonatype.com/artifact/io.github.giulong/spectrum){:target="_blank"} you can find the snippet for every build tool.

{% include copyCode.html %}

Expand All @@ -65,19 +66,7 @@ project:
</dependency>
```

## Gradle

{% include copyCode.html %}

```gradle
dependencies {
testImplementation group: 'io.github.giulong', name: 'spectrum', version: '1.26.1'
}
```

## Test creation

In general, all you need to do is create a **JUnit 6** test class extending the `SpectrumTest` class:
Then, you need to create a **JUnit 6** test class extending `SpectrumTest`:

{% include copyCode.html %}

Expand All @@ -94,7 +83,23 @@ public class HelloWorldIT extends SpectrumTest<Void> {
}
```

After running it, you will find a html report in the `target/spectrum/reports` folder.
As third and last step, you need create a basic `src/test/resources/configuration.yaml`:

{% include copyCode.html %}

```yaml
application:
baseUrl: https://the-internet.herokuapp.com/ # Change this with your app's landing page

video: # video of the execution attached to the html report (will be empty since the test is doing nothing)
frames:
- autoBefore

extent:
openAtEnd: true # the html report will open automatically in your browser after the execution
```

Now you can run the test, and the generated report will automatically open in your browser.

> ⚠️ **Running with Maven**<br/>
> If you run tests with Maven, the name of your test classes should end with `IT` as in the example above (`HelloWorldIT`),
Expand Down Expand Up @@ -1580,6 +1585,9 @@ If you'd like to customise the js applied when highlighting, you have 2 options

JSON Schema really comes in handy when editing `configuration*.yaml`, since it allows you to have autocompletion
and a non-blocking validation (just warnings).

<video controls="" width="100%" src="assets/videos/json-schema.mov" type="video/mp4"></video>

This is the list of the available schemas, be sure to pick the right one according to the version of Spectrum you are using.

> 💡 **Tip**<br/>
Expand Down
Binary file added docs/assets/videos/json-schema.mov
Binary file not shown.
19 changes: 6 additions & 13 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<version>${revision}</version>
<packaging>pom</packaging>
<name>Spectrum Aggregate</name>
<description>E2E Test Automation Framework</description>
<description>Modern Selenium Framework</description>
<url>https://github.com/giulong/spectrum</url>

<developers>
Expand Down Expand Up @@ -52,7 +52,7 @@
<simplejavamail.version>8.12.6</simplejavamail.version>
<jsonschemagenerator.version>4.38.0</jsonschemagenerator.version>
<slf4j.version>2.0.17</slf4j.version>
<selenium.version>4.36.0</selenium.version>
<selenium.version>4.37.0</selenium.version>
</properties>

<profiles>
Expand Down Expand Up @@ -195,7 +195,7 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.19</version>
<version>1.5.20</version>
</dependency>
<dependency>
<groupId>org.codehaus.janino</groupId>
Expand Down Expand Up @@ -250,7 +250,7 @@
<dependency>
<groupId>net.datafaker</groupId>
<artifactId>datafaker</artifactId>
<version>2.5.1</version>
<version>2.5.2</version>
</dependency>

<dependency>
Expand Down Expand Up @@ -323,7 +323,7 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>11.1.0</version>
<version>12.1.0</version>
</dependency>
<dependency>
<groupId>com.github.sevntu-checkstyle</groupId>
Expand Down Expand Up @@ -411,6 +411,7 @@
<junit.jupiter.execution.parallel.enabled>true</junit.jupiter.execution.parallel.enabled>
<junit.jupiter.execution.parallel.mode.default>same_thread</junit.jupiter.execution.parallel.mode.default>
<junit.jupiter.execution.parallel.mode.classes.default>concurrent</junit.jupiter.execution.parallel.mode.classes.default>
<junit.jupiter.execution.timeout.testable.method.default>5 m</junit.jupiter.execution.timeout.testable.method.default>
</systemPropertyVariables>
</configuration>
</plugin>
Expand Down Expand Up @@ -525,10 +526,6 @@
<token><![CDATA[<version>.*</version>]]></token>
<value><![CDATA[<version>${revision}</version>]]></value>
</replacement>
<replacement>
<token>testImplementation group: 'io.github.giulong', name: 'spectrum', version: '.*'</token>
<value>testImplementation group: 'io.github.giulong', name: 'spectrum', version: '${revision}'</value>
</replacement>
</replacements>
</configuration>
</execution>
Expand All @@ -545,10 +542,6 @@
<token><![CDATA[<version>.*</version>]]></token>
<value><![CDATA[<version>${revision}</version>]]></value>
</replacement>
<replacement>
<token>testImplementation group: 'io.github.giulong', name: 'spectrum', version: '.*'</token>
<value>testImplementation group: 'io.github.giulong', name: 'spectrum', version: '${revision}'</value>
</replacement>
</replacements>
</configuration>
</execution>
Expand Down
4 changes: 2 additions & 2 deletions spectrum/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<artifactId>spectrum</artifactId>
<name>Spectrum</name>
<description>E2E Test Automation Framework</description>
<description>Modern Selenium Framework</description>
<url>https://github.com/giulong/spectrum</url>

<developers>
Expand Down Expand Up @@ -215,7 +215,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.13</version>
<version>0.8.14</version>
<configuration>
<excludes>
<exclude>io/github/giulong/spectrum/pojos/**/*</exclude>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package io.github.giulong.spectrum.extensions.resolvers.bidi;

import io.github.giulong.spectrum.utils.Configuration;
import lombok.extern.slf4j.Slf4j;
import org.jspecify.annotations.NonNull;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.bidi.HasBiDi;

import static io.github.giulong.spectrum.extensions.resolvers.DriverResolver.DRIVER;
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;

@Slf4j
public abstract class BiDiTypeBasedParameterResolver<T> implements ParameterResolver {

private final Configuration configuration = Configuration.getInstance();

abstract String getKey();

abstract Class<T> getType();
Expand All @@ -31,7 +33,7 @@ public final T resolveParameter(@NonNull final ParameterContext parameterContext
final WebDriver driver = store.get(DRIVER, WebDriver.class);
final String key = getKey();

if (!isBiDiEnabledFor(driver)) {
if (!configuration.getDrivers().isBiDi()) {
log.debug("BiDi disabled. Avoid resolving {}", key);
return null;
}
Expand All @@ -42,8 +44,4 @@ public final T resolveParameter(@NonNull final ParameterContext parameterContext
store.put(key, t);
return t;
}

boolean isBiDiEnabledFor(final WebDriver driver) {
return driver instanceof HasBiDi && ((HasBiDi) driver).maybeGetBiDi().isPresent();
}
}
Loading
Loading