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
73 changes: 73 additions & 0 deletions docs/Keywords/API/Request_Builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,79 @@ api.post("serviceName").appendDefaultContentCharsetToContentTypeIfUndefined(fals

#### _** \*Please check the [Response Validations](https://shafthq.github.io/docs/Keywords/API/Response_Validations) as we can make many assertions and verifications on API response by using the Class [RestValidationsBuilder](https://shafthq.github.io/SHAFT_ENGINE/apidocs/com/shaft/validation/RestValidationsBuilder.html)\* **_

## GraphQL API Testing

SHAFT supports GraphQL requests out of the box through `sendGraphQlRequest()`. You can send queries, mutations, and fragments without any additional dependencies.

### Simple GraphQL Query

```java title="GraphQLSimpleQuery.java"
SHAFT.API api = new SHAFT.API("https://api.example.com");

Response response = api.sendGraphQlRequest(
"/graphql",
"{ users { id name email } }"
).perform();

api.assertThatResponse()
.extractedJsonValue("$.data.users[0].name")
.isEqualTo("Alice")
.perform();
```

### GraphQL Query with Variables

```java title="GraphQLWithVariables.java"
SHAFT.API api = new SHAFT.API("https://api.example.com");

String query = "query GetUser($id: ID!) { user(id: $id) { name email role } }";
String variables = "{\"id\": \"123\"}";

api.sendGraphQlRequest("/graphql", query, variables).perform();

api.assertThatResponse()
.extractedJsonValue("$.data.user.email")
.contains("@example.com")
.perform();
```

### GraphQL with Authentication Header

```java title="GraphQLWithAuth.java"
SHAFT.API api = new SHAFT.API("https://api.example.com");

api.sendGraphQlRequest("/graphql", "{ me { name } }")
.addHeader("Authorization", "Bearer mytoken123")
.perform();

api.assertThatResponse().body().contains("\"name\"").perform();
```

### GraphQL Mutation

```java title="GraphQLMutation.java"
SHAFT.API api = new SHAFT.API("https://api.example.com");

String mutation = "mutation CreateUser($input: CreateUserInput!) { createUser(input: $input) { id name } }";
String variables = "{\"input\": {\"name\": \"Bob\", \"email\": \"bob@example.com\"}}";

api.sendGraphQlRequest("/graphql", mutation, variables)
.addHeader("Authorization", "Bearer admintoken")
.setTargetStatusCode(200)
.perform();

api.assertThatResponse()
.extractedJsonValue("$.data.createUser.name")
.isEqualTo("Bob")
.perform();
```

:::tip
GraphQL always uses HTTP `POST` under the hood. SHAFT automatically sets the `Content-Type: application/json` header and wraps your query and variables in the correct payload format.
:::

---

## Sample Code Snippet
```java
public class Test_Api {
Expand Down
132 changes: 132 additions & 0 deletions docs/Keywords/GUI/Async_Element_Actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
id: Async_Element_Actions
title: Async Element Actions
sidebar_label: Async Element Actions
description: "Run SHAFT element actions concurrently using Java virtual threads — improve test speed with non-blocking parallel interactions."
keywords: [SHAFT, async element actions, parallel element actions, virtual threads, concurrent selenium, non-blocking actions]
tags: [web, element, async, performance, java21]
---

## Overview

SHAFT supports non-blocking element actions via Java 21 virtual threads through `driver.async().element()`. Actions queued on the async executor run in parallel and return immediately, letting you kick off multiple interactions concurrently and synchronize at a chosen point.

This is useful when:
- Filling a long form where fields are independent and can be typed into simultaneously
- Triggering multiple UI actions that don't need to happen in strict sequence
- Reducing wall-clock test execution time without sacrificing accuracy

---

## Basic Usage

### Parallel Form Fill

```java title="AsyncFormFill.java"
// Queue multiple element actions — they start concurrently
driver.async().element()
.type(By.id("firstName"), "Alice")
.type(By.id("lastName"), "Smith")
.type(By.id("email"), "alice@example.com")
.select(By.id("country"), "United States")
.synchronize(); // blocks the current thread until all virtual threads complete; propagates any action failures as exceptions
```

### Parallel Click and Screenshot

```java title="AsyncClickAndCapture.java"
driver.async().element()
.click(By.id("submitBtn"))
.captureScreenshot(By.id("confirmationMessage"))
.join(); // alternative to synchronize()
```

:::note
`.synchronize()` and `.join()` are equivalent — use whichever reads more naturally in context.
:::

---

## Synchronisation Methods

After queuing async actions, call one of the following to block until all actions complete:

| Method | Description |
|:-------|:------------|
| `.synchronize()` | Waits for all queued async actions to complete |
| `.join()` | Alias for `.synchronize()` |
| `.sync()` | Alias for `.synchronize()` |

```java title="AsyncSynchronise.java"
driver.async().element()
.type(By.id("fieldA"), "value1")
.type(By.id("fieldB"), "value2")
.type(By.id("fieldC"), "value3")
.sync(); // equivalent to .synchronize() and .join()
```

---

## Complete Example: Registration Form

```java title="AsyncRegistrationTest.java"
import com.shaft.driver.SHAFT;
import org.openqa.selenium.By;
import org.testng.annotations.*;

public class AsyncRegistrationTest {
SHAFT.GUI.WebDriver driver;

@BeforeMethod
public void setup() {
driver = new SHAFT.GUI.WebDriver();
}

@Test
public void registerUserWithAsyncActions() {
driver.browser().navigateToURL("https://example.com/register");

// Fill all fields in parallel using virtual threads
driver.async().element()
.type(By.id("firstName"), "Alice")
.type(By.id("lastName"), "Smith")
.type(By.id("email"), "alice@example.com")
.type(By.id("phone"), "+1-555-0100")
.select(By.id("country"), "United States")
.synchronize();

// Proceed sequentially once the form is filled
driver.element().click(By.id("submitBtn"));

driver.assertThat().browser().url().contains("/success").perform();
}

@AfterMethod
public void teardown() {
driver.quit();
}
}
```

---

## When to Use Async vs. Synchronous Actions

| Scenario | Recommendation |
|:---------|:---------------|
| Independent form fields with no DOM side-effects | ✅ Use async |
| Fields where typing in one triggers a validation on another | ❌ Use standard sequential actions |
| Bulk data entry where order doesn't matter | ✅ Use async |
| Actions that depend on the result of a previous action | ❌ Use standard sequential actions |
| Capturing screenshots while another action runs | ✅ Use async |

:::tip
Async actions are best suited for **write** operations (type, select, click) that operate on independent elements. Avoid using them when one action's outcome affects the next element's state.
:::

---

## Additional Resources

- [Element Actions](./Element_Actions) — standard synchronous element API
- [SHAFT_ENGINE source — AsyncElementActions](https://github.com/ShaftHQ/SHAFT_ENGINE/tree/master/src/main/java/com/shaft/gui/element)
Loading
Loading