or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-utilities.mdasync.mdconfig.mdconfiguration.mddebugging.mdevents.mdindex.mdqueries.mdquery-helpers.mdrole-utilities.mdscreen.mdutilities.mdwithin.md

async-utilities.mddocs/

0

# Async Utilities

1

2

Promise-based utilities for handling asynchronous DOM changes and waiting for elements to appear or disappear. Essential for testing applications with dynamic content, async operations, and time-dependent UI changes.

3

4

## Capabilities

5

6

### Wait For

7

8

Wait for asynchronous operations to complete by polling a callback function until it succeeds or times out.

9

10

```typescript { .api }

11

function waitFor<T>(

12

callback: () => Promise<T> | T,

13

options?: waitForOptions,

14

): Promise<T>;

15

16

interface waitForOptions {

17

/** Container to observe for mutations (defaults to document) */

18

container?: HTMLElement;

19

/** Maximum time to wait in milliseconds (defaults to 1000ms) */

20

timeout?: number;

21

/** How often to check the callback in milliseconds (defaults to 50ms) */

22

interval?: number;

23

/** Custom error handler for timeout cases */

24

onTimeout?: (error: Error) => Error;

25

/** MutationObserver configuration for DOM change detection */

26

mutationObserverOptions?: MutationObserverInit;

27

}

28

```

29

30

**Usage Examples:**

31

32

```typescript

33

import { waitFor, getByText } from "@testing-library/dom";

34

35

// Wait for element to appear after async operation

36

await waitFor(() => {

37

expect(getByText(container, "Loading complete")).toBeInTheDocument();

38

});

39

40

// Wait for element with custom timeout

41

await waitFor(

42

() => getByText(container, "Async content"),

43

{ timeout: 5000 }

44

);

45

46

// Wait for element to disappear

47

await waitFor(() => {

48

expect(queryByText(container, "Loading...")).not.toBeInTheDocument();

49

});

50

51

// Wait with custom interval for faster checking

52

await waitFor(

53

() => expect(getByTestId(container, "status")).toHaveTextContent("Ready"),

54

{ interval: 10 }

55

);

56

57

// Wait for specific container changes

58

const specificContainer = document.querySelector('.dynamic-section');

59

await waitFor(

60

() => getByText(specificContainer, "Updated content"),

61

{ container: specificContainer }

62

);

63

64

// Custom timeout error handling

65

await waitFor(

66

() => getByText(container, "Rare element"),

67

{

68

timeout: 3000,

69

onTimeout: (error) => {

70

return new Error(`Custom timeout message: ${error.message}`);

71

}

72

}

73

);

74

75

// Wait for multiple conditions

76

await waitFor(() => {

77

const button = getByRole(container, "button", { name: "Submit" });

78

const input = getByLabelText(container, "Email");

79

expect(button).not.toBeDisabled();

80

expect(input).toHaveValue("user@example.com");

81

});

82

83

// Wait for API response to update UI

84

async function submitForm() {

85

fireEvent.click(getByRole(container, "button", { name: "Submit" }));

86

87

await waitFor(() => {

88

expect(getByText(container, "Form submitted successfully")).toBeInTheDocument();

89

});

90

}

91

92

// Wait for animation to complete

93

await waitFor(() => {

94

const modal = getByRole(container, "dialog");

95

expect(modal).toHaveClass("fade-in-complete");

96

}, { timeout: 2000 });

97

```

98

99

### Wait For Element To Be Removed

100

101

Wait for element(s) to be removed from the DOM. Useful for testing element removal, modal closing, or content cleanup.

102

103

```typescript { .api }

104

function waitForElementToBeRemoved<T>(

105

callback: T | (() => T),

106

options?: waitForOptions,

107

): Promise<void>;

108

```

109

110

**Usage Examples:**

111

112

```typescript

113

import { waitForElementToBeRemoved, getByText, queryByText } from "@testing-library/dom";

114

115

// Wait for loading spinner to disappear

116

const loadingSpinner = getByText(container, "Loading...");

117

await waitForElementToBeRemoved(loadingSpinner);

118

119

// Wait using callback function (safer for elements that might not exist)

120

await waitForElementToBeRemoved(() => queryByText(container, "Loading..."));

121

122

// Wait for modal to be removed

123

const modal = getByRole(container, "dialog");

124

fireEvent.click(getByRole(modal, "button", { name: "Close" }));

125

await waitForElementToBeRemoved(modal);

126

127

// Wait for multiple elements to be removed

128

const notifications = getAllByRole(container, "alert");

129

fireEvent.click(getByRole(container, "button", { name: "Clear all" }));

130

await waitForElementToBeRemoved(notifications);

131

132

// Wait with custom timeout

133

await waitForElementToBeRemoved(

134

() => queryByTestId(container, "temporary-message"),

135

{ timeout: 5000 }

136

);

137

138

// Wait for element in specific container

139

const sidebar = document.querySelector('.sidebar');

140

await waitForElementToBeRemoved(

141

() => queryByText(sidebar, "Temporary item"),

142

{ container: sidebar }

143

);

144

145

// Combine with user interactions

146

async function closeModal() {

147

const modal = getByRole(container, "dialog");

148

const closeButton = getByRole(modal, "button", { name: "Close" });

149

150

fireEvent.click(closeButton);

151

152

// Wait for modal to be completely removed

153

await waitForElementToBeRemoved(modal);

154

}

155

156

// Wait for toast notification to auto-dismiss

157

async function showToast() {

158

fireEvent.click(getByRole(container, "button", { name: "Show notification" }));

159

160

// Verify toast appears

161

const toast = getByRole(container, "alert");

162

expect(toast).toBeInTheDocument();

163

164

// Wait for auto-dismiss after 3 seconds

165

await waitForElementToBeRemoved(toast, { timeout: 4000 });

166

}

167

```

168

169

## Advanced Usage Patterns

170

171

### Waiting for Network Requests

172

173

```typescript

174

// Wait for data to load after API call

175

async function loadUserData(userId: string) {

176

fireEvent.click(getByRole(container, "button", { name: `Load user ${userId}` }));

177

178

// Wait for loading state to appear

179

await waitFor(() => {

180

expect(getByText(container, "Loading user data...")).toBeInTheDocument();

181

});

182

183

// Wait for loading to complete and data to appear

184

await waitFor(() => {

185

expect(getByText(container, `User: ${userId}`)).toBeInTheDocument();

186

}, { timeout: 5000 });

187

188

// Ensure loading indicator is gone

189

await waitForElementToBeRemoved(() => queryByText(container, "Loading user data..."));

190

}

191

```

192

193

### Waiting for Form Validation

194

195

```typescript

196

async function testFormValidation() {

197

const emailInput = getByLabelText(container, "Email");

198

const submitButton = getByRole(container, "button", { name: "Submit" });

199

200

// Enter invalid email

201

fireEvent.change(emailInput, { target: { value: "invalid-email" } });

202

fireEvent.click(submitButton);

203

204

// Wait for validation error to appear

205

await waitFor(() => {

206

expect(getByText(container, "Please enter a valid email")).toBeInTheDocument();

207

});

208

209

// Enter valid email

210

fireEvent.change(emailInput, { target: { value: "user@example.com" } });

211

212

// Wait for error to disappear

213

await waitForElementToBeRemoved(() => queryByText(container, "Please enter a valid email"));

214

}

215

```

216

217

### Waiting with MutationObserver Options

218

219

```typescript

220

// Wait with specific DOM observation settings

221

await waitFor(

222

() => expect(getByTestId(container, "dynamic-list")).toHaveClass("loaded"),

223

{

224

mutationObserverOptions: {

225

attributes: true,

226

attributeFilter: ['class'],

227

subtree: true,

228

}

229

}

230

);

231

```

232

233

## Error Handling

234

235

Both functions will throw descriptive errors when timeouts occur:

236

237

```typescript

238

try {

239

await waitFor(() => {

240

getByText(container, "Element that never appears");

241

}, { timeout: 1000 });

242

} catch (error) {

243

// Error includes information about what was being waited for

244

console.log(error.message); // Includes debugging information

245

}

246

247

try {

248

const nonExistentElement = getByText(container, "Does not exist");

249

await waitForElementToBeRemoved(nonExistentElement);

250

} catch (error) {

251

// Handle case where element doesn't exist initially

252

console.log("Element was not found to begin with");

253

}

254

```

255

256

## Types

257

258

```typescript { .api }

259

interface waitForOptions {

260

container?: HTMLElement;

261

timeout?: number;

262

interval?: number;

263

onTimeout?: (error: Error) => Error;

264

mutationObserverOptions?: MutationObserverInit;

265

}

266

267

// waitFor return type is inferred from callback

268

function waitFor<T>(

269

callback: () => Promise<T> | T,

270

options?: waitForOptions,

271

): Promise<T>;

272

273

// waitForElementToBeRemoved always returns Promise<void>

274

function waitForElementToBeRemoved<T>(

275

callback: T | (() => T),

276

options?: waitForOptions,

277

): Promise<void>;

278

```