Skip to content

Commit

Permalink
Merge pull request #40 from Invictum/38_turn_narrative_into_function
Browse files Browse the repository at this point in the history
38 turn narrative into function
  • Loading branch information
Invictum authored Jul 25, 2018
2 parents 1065d43 + 9d431ed commit 545a9b4
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 98 deletions.
89 changes: 51 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,30 @@ Serenity integration with Report Portal

Module allows to report Serenity powered tests to [reportportal.io](http://reportportal.io). Supplies additional reporting facility to Serenity based test automation frameworks.

Setup
-------------
Table of Contents
-----------------
1. [Setup](#setup)
1. [Maven](#maven)
2. [Gradle](#gradle)
3. [Native Serenity reporting](#native-serenity-reporting)
2. [Integration configuration](#integration-configuration)
1. [Profiles](#profiles)
2. [Executors](#executors)
3. [Handler type (experimental feature)](#handler-type-experimental-feature)
4. [Narrative formatter](#narrative-formatter)
3. [Data mapping](#data-mapping)
4. [Versioning](#versioning)
5. [Important release notes](#important-release-notes)
6. [Limitations](#limitations)

## Setup

To add support of integration between Serenity and Report Portal simply add dependencies to your project based on used build tool.

> **Warning**
> Don't add any extra Report Portal listeners or agents. Integration is provided by single module for all available Serenity approaches
**Maven**
#### Maven

Edit project's `pom.xml` file
```
Expand All @@ -38,7 +54,7 @@ Report Portal core libraries are used, but they placed in a separate repository,
</repositories>
```

**Gradle**
#### Gradle

Edit `build.gradle` file in the project root
```
Expand Down Expand Up @@ -72,12 +88,11 @@ It is also possible to use Report portal integration with log frameworks in orde
> **Notice**
> Actually to add logs to Report Portal, they should be emitted in scope of test method, otherwise they will not be displayed at all
**Native Serenity reporting**
#### Native Serenity reporting

Serenity TAF may produce its own reporting facility via separate plugins. But `serenity-reportportal-integration` may be used in parallel with it or independently. Both reporting mechanisms should be configured accordingly and do not depends on each other.

Integration configuration
-------------
## Integration configuration

All available configurations are provided via `ReportIntegrationConfig` object. Each set method returns object itself, so chain of configuration is possible:
```
Expand All @@ -88,7 +103,7 @@ configuration.useHandler(HandlerType.TREE).useProfile(StepsSetProfile.TREE_OPTIM
> **Notice**
All integration configurations should be provided before Serenity facility init (For example on `@BeforeClass` method on the parent test class for jUnit style tests). Otherwise default values will be used.

**Profiles**
#### Profiles

Each Serenity `TestStep` object is passed through chain of configured `StepDataExtractors`. This approach allows to flexible configure reporting behaviour on a step level. By default integration provides following configuration profiles:

Expand All @@ -110,7 +125,7 @@ profile.registerProcessors(new StartStep(), new FinishStep());
ReportIntegrationConfig.get().useProfile(profile);
```

**Executors**
#### Executors

All step executors are available out of the box may be observed in `com.github.invictum.reportportal.extractor` package.
For now following processors are available:
Expand Down Expand Up @@ -157,7 +172,7 @@ public class GreetingExtractor implements StepDataExtractor {
Extracted collection of `EnhancedMessage` will be used to push logs to to Report Portal and their order will be based on timestamp.

**Handler type (experimental feature)**
#### Handler type (experimental feature)

Integration provides two strategies of storing Serenity's test data to Report Portal facility:
- *FLAT* (default behaviour) - Represents steps data as plain logs emitted to the test scope
Expand All @@ -173,23 +188,23 @@ Handler type may be changed with following configuration
ReportIntegrationConfig.get().useHandler(HandlerType.TREE);
```

**Narrative formatter**
#### Narrative formatter

By default, narrative is formatted as a bullet list before storing to the test description field. It is possible to alter this logic in accordance to project needs.
By default, narrative is formatted as a card with title and bullet list before storing to the test description field. It is possible to alter this logic in accordance to project needs.

To achieve it implement `NarrativeFormatter` interface and define your own implementation of formatter. For example
To achieve it supply `Function<Narrative, String>` function to configuration and define your own implementation logic
```
public class NumberedListFormatter implements NarrativeFormatter {
@Override
public String format(String[] strings) {
return IntStream.range(0, strings.length).mapToObj(index -> (index + 1) + ". " + strings[index])
.collect(Collectors.joining("\n"));
}
}
// Define Function<Narrative, String> that will format narrative as a numbered list
Function<Narrative, String> narrativeFormatter = narrative -> {
String[] strings = narrative.text();
return IntStream.range(0, strings.length).mapToObj(index -> (index + 1) + ". " + strings[index])
.collect(Collectors.joining("\n"));
};
// Add defined function to the configuration
ReportIntegrationConfig.get().useNarrativeFormatter(narrativeFormatter);
```

Code snippet above will format narrative lines as a numbered list.
Code snippet above will format narrative lines as a numbered list
```
Initial lines
line 1, line 2
Expand All @@ -199,15 +214,12 @@ Result lines
2. line 2
```

Custom `NarrativeFormatter` should be registered via configuration
```
ReportIntegrationConfig.get().useNarrativeFormatter(new NumberedListFormatter());
```
> **Info**
> Text returned by `Function<Narrative, String>` function is treated as markdown, so markdown syntax could be used
Data mapping
-------------
## Data mapping

Serenity framework and Report Portal facility have a different entities structure. This section explains how data related to each other in mentioned systems.
Serenity framework and Report Portal facility have a different entities structure. This section explains how data relates to each other.

**Name** relation is straightforward.

Expand All @@ -233,14 +245,15 @@ When for simple scenario
Then for simple scenario
```

For jUnit there is a `@Narrative` annotation. Each line of narrative text will be concatinated
For jUnit there is a `@Narrative` annotation
```
@RunWith(SerenityRunner.class)
@Narrative(text = {"line 1", "line 2"})
public class SimpleTest {
...
}
```
Narrative is transformed with function that may be passed to integration configuration

**Tags** supplying depends on test source.
For jBehave (BDD) tests tags is defined in Meta section with `@tag` or `@tags` keyword
Expand All @@ -265,8 +278,8 @@ public class SimpleTest {
}
```

Versioning
----------
## Versioning

Report Portal integration uses 3 digit version format - x.y.z

**z** - regular release increment version. Includes bugfix and extending with minor features. Also includes Serenity and Report Portal modules versions update. Backward compatibility is guaranteed.
Expand All @@ -275,18 +288,18 @@ Report Portal integration uses 3 digit version format - x.y.z

**x** - major version update. Dramatically changed integration architecture. Backward compatibility doesn't guaranteed. Actually increment of major version is not expected at all

Important release notes
-----------------------
## Important release notes

Important release notes are described below. Use [releases](https://github.com/Invictum/serenity-reportportal-integration/releases) section for details regarding regular release notes.

Version | Note
---------------|---------------------------
1.0.0 - 1.0.6 | Supports RP v3 and below
1.1.0 - 1.1.3 | Minor version update due RP v4 release. Versions older than 1.1.0 are not compatible with RP v4+ and vise versa
1.2.0+ | Minor version updated due Configuration approach refactoring. New configuratiion approach is not compatible with versions under 1.2.0
1.2.0+ | Minor version updated due internal mechanisms approach major refactoring

## Limitations

Limitations
-------------
Integration does not support concurrency for parametrized Serenity tests execution.

Report Portal launch finish timestamp is calculated before Java VM shutdown. Overall launch duration will also include the time of Serenity report generation.
Report Portal launch finish timestamp is calculated before Java VM shutdown. Overall launch duration will also include the time of Serenity report generation (only in case if both RP and Serenity reporting are used).

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

import com.github.invictum.reportportal.handler.HandlerType;
import com.github.invictum.reportportal.injector.IntegrationInjector;
import net.thucydides.core.annotations.Narrative;

import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* Configuration entry point for integration.
Expand All @@ -12,7 +16,7 @@
public class ReportIntegrationConfig {

private StepsSetProfile profile;
private NarrativeFormatter narrativeFormatter;
private Function<Narrative, String> narrativeFormatter;
private HandlerType handlerType;

/**
Expand All @@ -39,14 +43,14 @@ public StepsSetProfile profile() {
}

/**
* Defines {@link NarrativeFormatter} configuration
* Defines narrative format {@link Function}
*/
public ReportIntegrationConfig useNarrativeFormatter(NarrativeFormatter narrativeFormatter) {
public ReportIntegrationConfig useNarrativeFormatter(Function<Narrative, String> narrativeFormatter) {
this.narrativeFormatter = Objects.requireNonNull(narrativeFormatter, "Narrative formatter could not be null");
return this;
}

public NarrativeFormatter narrativeFormatter() {
public Function<Narrative, String> narrativeFormatter() {
return narrativeFormatter;
}

Expand All @@ -67,7 +71,11 @@ public HandlerType handlerType() {
*/
public void resetToDefaults() {
this.profile = StepsSetProfile.DEFAULT;
this.narrativeFormatter = new NarrativeBulletListFormatter();
// Returned text is treated by RP as markdown
this.narrativeFormatter = narrative -> {
String text = Stream.of(narrative.text()).map(item -> "* " + item).collect(Collectors.joining("\n"));
return narrative.title().isEmpty() ? text : String.format("**%s**\n", narrative.title()) + text;
};
this.handlerType = HandlerType.FLAT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
import com.github.invictum.reportportal.injector.IntegrationInjector;
import com.google.inject.Inject;
import io.reactivex.Maybe;
import net.thucydides.core.annotations.Narrative;
import net.thucydides.core.model.Story;
import net.thucydides.core.model.TestOutcome;
import net.thucydides.core.requirements.annotations.NarrativeFinder;

import java.time.Duration;
import java.util.Calendar;
import java.util.Date;
import java.util.function.Function;

/**
* Handler builds Serenity's {@link TestOutcome} in Report Portal as flat sequence of logs
Expand Down Expand Up @@ -41,11 +43,10 @@ public void startSuite(Class<?> storyClass) {
startSuite.setName(storyClass.getSimpleName());
startSuite.setStartTime(Calendar.getInstance().getTime());
/* Add narrative to description if present */
if (NarrativeFinder.forClass(storyClass).isPresent()) {
NarrativeFormatter narrativeFormatter = ReportIntegrationConfig.get().narrativeFormatter();
String description = narrativeFormatter.format(NarrativeFinder.forClass(storyClass).get().text());
startSuite.setDescription(description);
}
NarrativeFinder.forClass(storyClass).ifPresent(narrative -> {
Function<Narrative, String> narrativeFormatter = ReportIntegrationConfig.get().narrativeFormatter();
startSuite.setDescription(narrativeFormatter.apply(narrative));
});
suiteId = launch.startTestItem(startSuite);
}
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.github.invictum.reportportal;

import com.github.invictum.reportportal.handler.HandlerType;
import net.thucydides.core.annotations.Narrative;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mockito;

@RunWith(JUnit4.class)
public class ReportIntegrationConfigTest {
Expand Down Expand Up @@ -40,8 +42,12 @@ public void nullHandlerTypeTest() {

@Test
public void defaultNarrativeFormatterTest() {
Class actual = config.narrativeFormatter().getClass();
Assert.assertEquals(NarrativeBulletListFormatter.class, actual);
Narrative narrativeMock = Mockito.mock(Narrative.class);
Mockito.when(narrativeMock.title()).thenReturn("Title");
Mockito.when(narrativeMock.text()).thenReturn(new String[]{"line 1", "line 2"});
config.resetToDefaults();
String actual = config.narrativeFormatter().apply(narrativeMock);
Assert.assertEquals("**Title**\n* line 1\n* line 2", actual);
}

@Test(expected = NullPointerException.class)
Expand Down

0 comments on commit 545a9b4

Please sign in to comment.