The target readers of this book are developers responsible for implementation, automated testing, and CI/CD construction in the development and maintenance of this system. The contents described in this document relate to the application, development/CI/CD environment, and automated testing aspects of this system and its development and maintenance. Also, in these aspects, we define the deliverables created by developers, mainly rules for creating application source code, test scripts, build scripts, and configuration files, that is, implementation methods. What is subject to regularization is when describing source code in a file, dividing the described content into multiple files, dividing it into components according to the syntax of the programming language within the file, file placement directories, and their naming, etc. In this document, in the division of content described in this source code, a collection of described content of the same type is called a responsibility, and a collection assigned to the same type of responsibility is called a component. By visualizing the configuration of components and their interactions, we aim to help developers understand the rules.
applications
Here, we define an implementation method for applications to be developed in this system. First, define applications and their responsibilities and interactions. Next, the application is broken down into components and their responsibilities and interactions are defined. Finally, we will define the implementation and placement rules for each component.
application configuration
The system consists of two applications and a DB, Frontend and Backend.
Frontend is a web application implemented with SvelteKit. It provides users with a user interface that can be used in a browser. It also performs simple validation of user input and calls to web APIs.
Backend is a web API application implemented in Quarkus. Provides a web API for front-end applications. Within the Web API, strict validation of requests, DB transaction control, business logic, and DB access are performed.
component configuration
The components that make up the Frontend/Backend application of this system and their interactions are defined as follows.
The responsibilities of each component and the units that define the components are defined are defined as follows.
component | duties | Defined units |
---|---|---|
page |
It is responsible for arranging screen items, defining validations, handling screen events, and calling web APIs. |
1 per screen (URL) |
pageLoader |
It is responsible for data acquisition and initialization of input items using the Web API during screen initialization. |
1 per page |
UIComponent |
It is responsible for making the screen into parts. |
Units that are easy to reuse |
Controllers |
It is responsible for defining web API endpoints. |
1 per entity |
Validator |
It is responsible for correlation validation. |
1 per Controller |
service |
It is responsible for transaction control and processing flow control within a transaction. |
1 per entity |
Logic |
It is responsible for processing that does not require access to external resources during service processing. |
1 per Service |
Repository |
Responsible for DB access and O/R mapping. |
1 per entity |
An object for passing data between components is defined as follows.
objects | The data to be represented | Defined units |
---|---|---|
Model |
Frontend web API requests and responses |
1 per DTO |
DTO |
Web API requests and responses in Backend |
1 per entity |
Entity |
DB records |
1 per DB table |
Frontend
package configuration
The FRONT project package structure is based on the SvelteKit project structure.
📁 svqk-front
└── 📁 src
├── 📁 lib -- 1
│ ├── 📁 arch -- 2
│ │ └── 📁 (function)
│ │ ├── 📄 *.svelte
│ │ └── 📄 *.ts
│ └── 📁 domain -- 3
│ └── 📁 (domain)
│ ├── 📄 *.svelte
│ └── 📄 *.ts
└── 📁 routes -- 4
└── 📁 (path...)
├── 📄 +page.svelte
└── 📄 +page.ts
-
This is the directory where libraries are placed. The files under this can be imported using paths starting with `$lib`.
-
This is a directory where libraries of common functions are placed. Under this, a directory is created for each function, and UIComponents and utilities are arranged.
-
A directory where domain-specific libraries are located. Under this, a directory is created for each domain, and UIComponents and utilities are placed.
-
This is the directory used by SvelteKit Routing. Under this, a directory is created for each URL hierarchy, and Page and PageLoader are arranged.
See the SvelteKit documentation for details on the SvelteKit project structure. |
page
Page is a component responsible for arranging screen items, defining validations, handling screen events, and calling web APIs.
Page is used in SvelteKit routing
+page.svelte
Implement it in a file.
+page.svelte
The relationship between files and Routing is as follows.
-
+page.svelte
Place the files at any level below src/routes. -
+page.svelte
The path below src/routes where the file is placed is the path of the URL to access this screen.-
examples
Configuration: src/routes/a/b/c/+page.svelte
URL: http://host:port/a/b/c
-
SvelteKit's routing and
|
The implementation details of Page are as follows.
<script lang="ts">
// script section (1)
</script>
(2)
<!-- markup section -->
1 | The script section implements validation definitions, screen event handling, web API calls, etc. in TypeScript. |
2 | The markup section implements the arrangement of screen items using HTML+ Svelte syntax. |
pageLoader
PageLoader is a component responsible for retrieving data and initializing input items using the Web API during screen initialization.
PageLoader is used with SvelteKit loading data
+page.ts
Implement it in a file.
-
+page.ts
The file is on the screen+page.svelte
Place it in the same directory as the file.
See the SvelteKit documentation for detailed specifications of SvelteKit's loading data. |
import type { PageLoad } from './$types';
import { env } from '$env/dynamic/public';
(1)
export const load: PageLoad = async ({ fetch }) => {
const response = await fetch(`${env.PUBLIC_BACKEND_URL}/api/hello/1`);
const hello = await response.json();
(2)
return {
hello
};
};
1 | Define a load function. The load function is executed when the URL of the corresponding screen is accessed. |
2 | The data required by Page is returned as an object. |
<script lang="ts">
import type { PageData } from './$types';
(1)
let { data }: { data: PageData } = $props();
const hello = data.hello;
</script>
(2)
<h1 id="message">{hello.message}</h1>
1 | Declare variables to store objects returned by PageLoader. |
2 | Data acquired by PageLoader via this variable can be viewed. |
Backend
package configuration
📁 svqk-back
└── 📁 src/main/java
└── 📁 {project-package}
├── 📁 arch
│ └── 📁 (function)
├── 📁 domain
│ └── 📁 (domain)
│ ├── 📄 *Service.java
│ └── 📄 *Repository.java
└── 📁 interfaces
└── 📁 (domain)
├── 📄 *Controller.java
└── 📄 *Dto.java
Controllers
Controller is a component that acts as an endpoint for the Web API. It receives an HTTP request from a client and returns an HTTP response to it. The processing flow within the Web API is controlled by controlling the execution order and input/output of the Validator, Factory, and Service. The Controller implementation uses Jakarta REST.
package dev.aulait.svqk.interfaces.hello;
import dev.aulait.svqk.domain.hello.HelloEntity;
import dev.aulait.svqk.domain.hello.HelloService;
import jakarta.validation.Valid;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import lombok.RequiredArgsConstructor;
@Path(HelloController.HELLO_PATH) (1)
@RequiredArgsConstructor (2)
public class HelloController {
private final HelloService helloService; (3)
static final String HELLO_PATH = "hello";
static final String HELLO_GET_PATH = "{id}";
@GET
@Path(HELLO_GET_PATH)
public HelloDto get(@PathParam("id") int id) { (4)
HelloEntity entity = helloService.find(id);
return HelloDto.builder().id(entity.getId()).message(entity.getMessage()).build();
}
@POST
public int save(@Valid HelloDto dto) { (4)
HelloEntity entity = HelloEntity.builder().id(dto.getId()).message(dto.getMessage()).build();
HelloEntity savedEntity = helloService.save(entity);
return savedEntity.getId();
}
}
1 | @Path
Set it to the Controller class. This makes this Controller class an endpoint for the Web API and is recognized by Quarkus.
|
2 | @RequiredArgsConstructor
Set it to the Controller class. This will automatically generate a constructor with a private final field as an argument during compilation.
|
3 | The component used by the Controller is defined as a private final field. This field injects an instance of the corresponding component when Quarkus starts. |
4 |
Define methods that serve as endpoints for the Web API. The method is an annotation representing the HTTP Method of the Web API (
@GET
,
@POST
etc.) is set.
|
See the Quarkus guide for details on Jakarta REST features that can be used in Controller implementations. |
service
Service is a component responsible for transaction processing. The flow of transaction processing is controlled by controlling the execution order and input/output of Repository and Logic. JTA and CDI are used to implement the Service.
package dev.aulait.svqk.domain.hello;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
@ApplicationScoped (1)
@RequiredArgsConstructor (2)
public class HelloService {
private final HelloRepository helloRepository; (3)
public HelloEntity find(int id) { (4)
}
@Transactional
public HelloEntity save(HelloEntity entity) { (4)
}
}
1 | @ApplicationScoped
Set it to the Service class. This allows instances of the Service class to be used as CDI managed beans.
|
2 | @RequiredArgsConstructor
Set it to the Service class. This makes it possible to use a constructor with a private final field as an argument without implementing it.
|
3 | Define components used by the service as private final fields. This field injects the corresponding component instance when Quarkus starts. |
4 |
A method is defined for each transaction process. What is the processing method for writing to the DB
@Transactinal
Set it up.
|
See the Quarkus documentation for details on JTA features available with Quarkus. |
Repository
Repository is a component responsible for DB access and O/R mapping. The Repository implementation uses JPA and Spring Data JPA.
package dev.aulait.svqk.domain.hello;
import org.springframework.data.jpa.repository.JpaRepository;
public interface HelloRepository extends JpaRepository<HelloEntity, Integer> { (1)
}
1 | JpaRepository
It inherits Type parameters specify entity and entity ID types.
|
For details on JPA and Spring Data JPA features available in Quarkus, see the Quarkus documentation. |
DTO
DTO is an object representing Web API requests and responses.
package dev.aulait.svqk.interfaces.hello;
import lombok.Builder;
import lombok.Data;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@Data (1)
@Builder
public class HelloDto {
@Schema(required = true, readOnly = true) (2)
private Integer id;
private String message;
}
1 | @Data
Set it to the DTO class. Thus, field getters, setters, etc. are automatically generated.
|
2 |
Define fields that are properties of requests and responses.
|
development environment
Development environment configuration
Project structure
This system stores materials (source files, configuration files) by dividing them into projects for each role. The project and main storage materials are as follows.
projects | Main storage materials | |
---|---|---|
svqk |
Materials related to application development and testing are stored as child projects for each.
|
|
svqk-container |
It stores materials for creating containers to be used in local development environments and CI.
|
|
svqk-migration |
Stores materials for DB migration using Flyway.
|
|
svqk-entity |
Generate JPA Entities and store materials for making them into libraries.
|
|
svqk-back |
Stores Backend materials. This project is based on one created with the Quarkus Maven Plugin.
|
|
svqk-front |
Stores Frontend materials. This project is based on one created from a SvelteKit template.
|
|
svqk-e2etest |
Stores materials for end to end tests. This project is based on something created from a Playwright template.
|
Build Configurations
This section explains the processing within the setup command and how to implement it.
# Windows
mvnw install -P setup
#macOS
./mvnw install -P setup
When the setup command is executed, each project is built sequentially. The process for these builds is shown below.
|
The commands executed in each project build and their processing details are as follows. (Commands are listed from top to bottom in order of execution.)
Project | Command | process |
---|---|---|
container |
MVNW RESOURCES: resources
|
Creating an.env file used by Docker Compose
|
migration |
MVNW Flyway: Clean
|
DB Schema Initialization
|
Front |
pnpm install
|
Installing packages used by the front project
|
Entity |
mvnw compiler:compile
|
Compile entity Java files
|
Buck |
MVNW RESOURCES: resources
|
Create an application.properties file for Quarkus to use
|
e2etest |
pnpm install
|
Installing packages used by the e2etest project
|
The above command is Maven's Build life cycle It has been integrated into.
container
Here, I will explain the container project build configuration.
Build phase | process |
---|---|
Process-resources |
The Maven Resources Plugin copies the src/main/resources/.env file directly under the container project. At this time, some environment variables (DB connection information, etc.) in the.env file are replaced with project property values using the Filter function of the plug-in.
src/main/resources/.env file contents
.env content copied directly under the container project
This.env file is intended to be used as an environment variable for Docker Compose which is subsequently launched. |
compile |
The Maven Exec Plugin will execute the following command.
This will start Docker Compose according to the compose.yml directly under the container project, and the DBMS can be used. |
migration
Here, I will explain the migration project build configuration. Since the migration project has set the container project as dependency, it is executed after the container project is built.
Build phase | process |
---|---|
compile |
If the setup profile is valid, the Flyway Maven Plugin
|
Front
Here, I will explain the build configuration of the front project.
Build phase | process |
---|---|
Generate-sources |
If the setup profile is valid, the Maven Exec Plugin will execute the following command.
|
Generate-sources |
The Maven Exec Plugin will execute the following command.
The pnpm build command builds the FRONT project as an SPA. The materials after the build are generated in the build directory directly under the front project. |
Process-resources |
The Maven Resources Plugin will copy the following.
resources/.env file contents
.env content copied directly under the front project
|
process-classes |
The Maven Resources Plugin will copy the following.
References: Webjars |
Pacakge |
The Maven JAR Plugin will generate a JAR file containing materials after the FRONT project has been built. |
Buck
Here, I will explain the back project build configuration. Since the back project has set the front project as dependency, it is executed after the front project is built.
Build phase | process |
---|---|
Process-resources |
The Maven Resources Plugin copies the src/main/resources/application.properties file into the target/classes directory. At this time, some property values (DB connection information, etc.) in the application.properties file are replaced with project property values using the Filter function of the plug-in.
src/main/resources/application.properties file
application.properties file copied to target/classes directory
|
package |
The Maven JAR Plugin builds the BACK project and generates a JAR file.
|
Integration-test |
Maven Failsafe Plugn runs test classes (*it.java) under the src/integration-test/java directory. The test class assumes the @QuarkusIntegrationTest annotation has been declared. This is intended to automatically start Quarkus when running integration-test. References: Using @QuarkusIntegrationTes t |
e2etest
Here, I will explain the build structure of the e2etest project. Since the e2etest project has set the back project as a dependency, it runs after the back project is built.
Build phase | process |
---|---|
Generate-sources |
If the setup profile is valid, the Maven Exec Plugin will execute the following command.
|
Process-resources |
The Maven Resources Plugin copies the resources/.env file directly under the e2etest project. At this time, some strings in the.env file are replaced with project property values by the filter function of the plug-in. |
Pre-integration-testing |
The Maven Exec Plugin will execute the following command.
As a result, Docker Compose is started according to the compose.yml directly under the e2etest project, and the Backend container can be used. |
Integration-test |
The Maven Exec Plugin will execute the following command.
This will run PlayWright tests (*.spec.ts) under the tests directory. |
post-intgration-test |
The Maven Exec Plugin will execute the following command.
This will stop and remove the Backend container. Also, if the browse-e2etest profile is valid, the browser will launch and the Playwright test report will be displayed. |
Local development environment
execution environment
Development support
formatter
The formatters used in this project are all VSCode extensions, and they are configured so that the format is automatically executed when the source file is saved in VSCode. The formatter for each language in the source file is as follows.
languages | Formatter (VSCode Extension) |
---|---|
html |
esbenp.prettier-vscode |
Java |
josevseb.google-java-format-for-vs-code
|
Javascript |
esbenp.prettier-vscode |
json |
esbenp.prettier-vscode |
JSONC |
esbenp.prettier-vscode |
Svelte |
esbenp.prettier-vscode |
typescript |
esbenp.prettier-vscode |
xml |
redhat.vscode-xml |
yaml |
redhat.vscode-yaml |
Installing these formatters, applying them per language, and running them when saved are all It's set in VSCode's workspace settings file (.code-workspace).
tests
Test automation guidelines
In this system, automatic tests are performed in the following 3 stages.
-
Unit test
-
Integration test
-
End to end test
The methods and test targets for each test are defined below.
-
Unit test
Test components that don't depend on other components by running them in JUnit. -
Integration test
Test by running Backend's REST API from JUnit while Backend and DB are linked. -
End to end test
Test by operating Frontend with Playwright while Frontend, Backend, and DB are linked.
Integration test
Integration tests confirm that the REST API provided by Backend works according to specifications. This is done by automating REST API calls with a test program. The application structure for Integration Test is shown below.
component configuration
The components that make up the Integration Test test program and their interactions are defined as follows.
The responsibilities of each component and the units that define the components are defined are defined as follows.
component | duties | File (class) units | Method units |
---|---|---|---|
testCase |
The REST API is called according to the test case and the expected values are verified. |
1 for each Controller being tested |
1 per test case |
RestClient |
It is responsible for calling the REST API and converting that request/response to DTO. |
1 for each Controller being tested |
1 per REST API call |
DataFactory |
We will generate a DTO containing the data required for the test. |
1 for each Controller being tested |
One for each data pattern required for testing |
testCase
TestCase is a component responsible for calling REST APIs and verifying expected values according to test cases.
package dev.aulait.svqk.interfaces.issue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import dev.aulait.svqk.arch.test.ConstraintViolationResponseDto;
import dev.aulait.svqk.arch.test.ValidationMessageUtils;
import io.quarkus.test.junit.QuarkusIntegrationTest;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.Test;
@QuarkusIntegrationTest (1)
class IssueControllerIT {
IssueClient client = new IssueClient(); (2)
@Test (3)
void testCrud() {
IssueDto issue = IssueDataFactory.createRandomIssue(); (4)
// Create
int issueId = client.create(issue); (5)
// Reference
IssueDto createdIssue = client.get(issueId);
assertEquals(issue.getSubject(), createdIssue.getSubject()); (6)
}
}
1 | Set @QuarkusIntegrationTest to the TestCase class. |
2 | Initialize the RestClient instance. |
3 | Following JUnit's approach, define a method and set @Test for each test case. |
4 | Use DataFactory to generate a DTO instance containing test data. |
5 | Use restClient to make REST API calls. |
6 | Expectations are verified using the JUnit API. |
RestClient
RestClient is a component responsible for calling the REST API and converting that request/response to DTO.
package dev.aulait.svqk.interfaces.issue;
import static dev.aulait.svqk.arch.test.RestAssuredUtils.given;
import static dev.aulait.svqk.interfaces.issue.IssueController.*;
import dev.aulait.svqk.arch.test.ConstraintViolationResponseDto;
public class IssueClient {
public Integer create(IssueDto issue) { (1)
return Integer.parseInt(
given() (2)
.body(issue)
.post(ISSUES_PATH)
.then()
.statusCode(200)
.extract()
.asString());
}
1 | Define methods to make REST API calls. The method argument is request dTO, and the return type is response dTO. |
2 | Implement REST API calls using RestAssured's API. |
DataFactroy
DataFactroy is a component responsible for generating DTOs that store data required for testing.
package dev.aulait.svqk.interfaces.issue;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.RandomStringUtils;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class IssueDataFactory {
public static IssueDto createRandomIssue() { (1)
IssueDto issue = new IssueDto();
issue.setSubject("test subject: " + RandomStringUtils.randomAlphanumeric(5));
IssueStatusDto status = new IssueStatusDto();
status.setId("1");
issue.setIssueStatus(status);
TrackerDto tracker = new TrackerDto();
1 |
Define a method for each data pattern required for the test. The example above is
subject
A random character string was stored in
IssueDto
It defines a method to create an instance.
|
End to end test
End to end testing verifies that the system works according to the use case scenario. This is done by automating user operations with a test program. The application structure for End to End Test is shown below.
The above is an application configuration defined by the application architecture, in which the user was replaced with a test program.
component configuration
The components that make up the test program and their interactions are defined as follows.
The responsibilities of each component and the units that define the components are defined are defined as follows.
component | duties | File (class) units | Method units |
---|---|---|---|
Spec |
Run test scenarios using Facace and PageObject. |
Units that make it easy to organize test scenarios |
1 per test scenario |
Facade |
Use PageObject to perform a series of screen operations and expected value verification across multiple screens. |
Units that make it easy to organize screens to be operated |
One for each set of operations that should be reused in multiple scenarios |
pageObject |
Use PageElement to perform a series of screen operations and verification of expected values within a single screen. |
1 per screen |
One for each series of operations within the same screen |
pageelement |
Use the API provided by basePageElement to perform screen manipulation and expected value verification. |
1 per screen |
screen element + one per operation/verification |
Factory |
Generate models to be used in tests. |
1 per model |
One for each data pattern to be set in the model to be created |
Spec
Spec is a component responsible for executing test scenarios. Test scenarios are implemented in Spec as Playwright test cases. In the test case, processing of screen operation and verification of expected values in line with the test scenario is implemented using Facace and PageObject.
import { test } from '@playwright/test';
import { IssueFacade } from '../facades/IssueFacade';
import { DryRun } from '../arch/DryRun';
import TopPage from '../pages/top/TopPage';
import IssueInputFactory from '../factories/IssueFactory';
(1)
test('CRUD of Issue', async ({ page }) => {
(2)
const dryRun = DryRun.build();
const topPage = new TopPage(page, dryRun);
(3)
const menuBar = await topPage.open();
let issueListPage = await menuBar.gotoIssueListPage();
let issueInputPage = await issueListPage.gotoNewIssuePage();
// Create
const issue = IssueInputFactory.createRandomIssue();
await issueInputPage.save(issue);
// Rererence
const issueFacade = new IssueFacade(dryRun);
issueInputPage = await issueFacade.referenceIssueBySubject(menuBar, issue.subject);
// ...
});
-
Define test cases using the test function provided by PlayWright. This is the entry point for tests that can be executed.
-
Initialize the components required to run the test scenario.
-
Implement test scenarios using facades and pageObjects. The 3 lines in the example above implement the scenario “open the top page, operate the menu bar to transition to the ticket list screen, and operate the ticket list screen to transition to the ticket registration screen”.
Facade
Facade is a component that is responsible for a series of screen operations and verification of expected values across multiple screens. Facade implements methods to do these using PageObject. The method is implemented so that the PageObject of the screen at the start is the argument, and the PageObject of the screen at the end is the return value.
import BaseFacade from '../arch/BaseFacade';
import MenuBar from '../pages/menu-bar/MenuBar';
export class IssueFacade extends BaseFacade {
(1)
async referenceIssueBySubject(menuBar: MenuBar, subject: string) {
this.logStart('Issue Reference');
(2)
const issueListPage = await menuBar.gotoIssueListPage();
await issueListPage.searchIssue({ text: subject });
const issueInputPage = await issueListPage.gotoIssueBySubject(subject);
(3)
return issueInputPage;
}
}
-
The Facade method has the following arguments.
-
PageObject of the screen that is the starting point for screen operations performed by Facade
-
Parameters used for screen operations performed by Facade
-
-
Implement screen operations performed by Facade using PageObject.
-
The PageObject of the screen at the end is returned as the return value of the method.
pageObject
PageObject is a component responsible for a series of screen operations within a screen and verification of expected values. PageObject implements methods that do these using PageElement.
import IssueInputPageElement from './IssueInputPageElement';
import type { IssueModel } from '../../api/Api';
import BasePageElement from '../../arch/BasePageElement';
export default class IssueInputPage {
private issueInputPageEl: IssueInputPageElement;
constructor(page: BasePageElement) {
(1)
this.issueInputPageEl = new IssueInputPageElement(page);
}
(2)
async save(issue: IssueModel) {
(3)
await this.issueInputPageEl.inputSubject(issue.subject);
await this.issueInputPageEl.inputDescription(issue.description!);
await this.issueInputPageEl.clickSaveBtn();
}
(4)
async expectIssue(issue: IssueModel) {
await this.issueInputPageEl.expectSubject(issue.subject);
await this.issueInputPageEl.expectDescription(issue.description);
}
}
-
Define methods to perform screen operations. In the example above, “was specified as an argument
issue
It defines a “method that performs an operation to save”. -
Use PageElement to implement a series of screen operations.
-
Define methods for validating expected values. In the example above, “was specified as an argument
issue
It defines a “method that verifies whether the screen state matches with”.
pageelement
PageElement is a component responsible for manipulating screen elements and verifying expected values. PageElemnt implements methods to do these using basePageElement.
import BasePageElement from '../../arch/BasePageElement';
(1)
export default class IssueInputPageElement extends BasePageElement {
get pageNameKey() {
return 'newIssue';
}
(2)
async inputSubject(subject: string) {
(3)
await this.inputText('#subject', subject);
}
(4)
async expectSubject(subject: string) {
await this.expectText('#subject', subject);
}
}
-
It inherits basePageElement, which is the common base class for PageElement. This allows developers to implement PageElement without being aware of PlayWright's API.
-
An operation for one screen item is defined as 1 method. In the example above”
題名
It defines a “method for inputting a string specified as an argument into an item”. -
Implement operations on screen elements using the APIs provided by basePageElement. In the example above, “locator
#subject
An operation called “inputting a character string specified as an argument to the screen element specified by” has been implemented. -
The verification of expected values for a single screen item is defined as 1 method.
Factory
Factory is a component responsible for generating models to be used in tests.
import type { IssueModel, IssueStatusModel } from '../api/Api';
import StringUtils from '../arch/StringUtils';
export default class IssueFactory {
static create() {
const issue = { issueStatus: {} as IssueStatusModel } as IssueModel;
return issue;
}
(1)
static createRandomIssue() {
const issue = this.create();
issue.subject = StringUtils.generateRandomString();
issue.description = `${issue.subject}の説明`;
return issue;
}
}
-
Implement a method to generate a Model to be used for testing. In the example above
題名
,説明`にランダムな文字列を持つ `issue
The model is being generated.