Merge branch 'foss42:main' into enhance-auth-fields

This commit is contained in:
Udhay Adithya
2025-07-21 11:57:18 +05:30
committed by GitHub
5 changed files with 2617 additions and 3 deletions

View File

@@ -142,7 +142,7 @@ Future<
// Process Results
if (result.isError) {
print("Pre-request script execution error: ${result.stringResult}");
// Handle error - maybe show in UI, keep original request/env
//TODO: Handle error - log this error in the logs console
} else if (result.stringResult.isNotEmpty) {
final resultMap = jsonDecode(result.stringResult);
if (resultMap is Map<String, dynamic>) {
@@ -153,7 +153,7 @@ Future<
Map<String, Object?>.from(resultMap['request']));
} catch (e) {
print("Error deserializing modified request from script: $e");
//TODO: Handle error - maybe keep original request?
//TODO: Handle error - log this error in the logs console
}
}
// Get Environment Modifications

View File

@@ -58,6 +58,7 @@ Future<RequestModel> handlePreRequestScript(
if (scriptResult.updatedEnvironment.isNotEmpty) {
debugPrint(
"Warning: Pre-request script updated environment variables, but no active environment was selected to save them to.");
return requestModel;
}
return newRequestModel;
}

View File

@@ -9,7 +9,6 @@ import 'helpers.dart';
void main() async {
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() async {
await testSetUpTempDirForHive();
});
@@ -627,4 +626,541 @@ void main() async {
container.dispose();
});
});
group('CollectionStateNotifier Scripting Tests', () {
late ProviderContainer container;
late CollectionStateNotifier notifier;
setUp(() {
container = createContainer();
notifier = container.read(collectionStateNotifierProvider.notifier);
});
test('should update request with pre-request script', () {
final id = notifier.state!.entries.first.key;
const preRequestScript = '''
ad.request.headers.set('Authorization', 'Bearer ' + ad.environment.get('token'));
ad.request.headers.set('X-Request-ID', 'req-' + Date.now());
ad.console.log('Pre-request script executed');
''';
notifier.update(id: id, preRequestScript: preRequestScript);
final updatedRequest = notifier.getRequestModel(id);
expect(updatedRequest?.preRequestScript, equals(preRequestScript));
});
test('should update request with post-response script', () {
final id = notifier.state!.entries.first.key;
const postResponseScript = '''
if (ad.response.status === 200) {
const data = ad.response.json();
if (data && data.token) {
ad.environment.set('authToken', data.token);
}
}
ad.console.log('Post-response script executed');
''';
notifier.update(id: id, postRequestScript: postResponseScript);
final updatedRequest = notifier.getRequestModel(id);
expect(updatedRequest?.postRequestScript, equals(postResponseScript));
});
test('should preserve scripts when duplicating request', () {
final id = notifier.state!.entries.first.key;
const preRequestScript = 'ad.console.log("Pre-request");';
const postResponseScript = 'ad.console.log("Post-response");';
notifier.update(
id: id,
preRequestScript: preRequestScript,
postRequestScript: postResponseScript,
);
notifier.duplicate(id: id);
final sequence = container.read(requestSequenceProvider);
final duplicatedId = sequence.firstWhere((element) => element != id);
final duplicatedRequest = notifier.getRequestModel(duplicatedId);
expect(duplicatedRequest?.preRequestScript, equals(preRequestScript));
expect(duplicatedRequest?.postRequestScript, equals(postResponseScript));
});
test('should clear scripts when set to empty strings', () {
final id = notifier.state!.entries.first.key;
// First add scripts
notifier.update(
id: id,
preRequestScript: 'ad.console.log("test");',
postRequestScript: 'ad.console.log("test");',
);
// Then clear scripts
notifier.update(
id: id,
preRequestScript: '',
postRequestScript: '',
);
final updatedRequest = notifier.getRequestModel(id);
expect(updatedRequest?.preRequestScript, equals(''));
expect(updatedRequest?.postRequestScript, equals(''));
});
test('should preserve scripts when clearing response', () {
final id = notifier.state!.entries.first.key;
const preRequestScript = 'ad.console.log("Pre-request");';
const postResponseScript = 'ad.console.log("Post-response");';
notifier.update(
id: id,
preRequestScript: preRequestScript,
postRequestScript: postResponseScript,
);
notifier.clearResponse(id: id);
final updatedRequest = notifier.getRequestModel(id);
// Scripts should be preserved when clearing response
expect(updatedRequest?.preRequestScript, equals(preRequestScript));
expect(updatedRequest?.postRequestScript, equals(postResponseScript));
});
test('should handle scripts with special characters and multi-line', () {
final id = notifier.state!.entries.first.key;
const complexPreScript = '''
// Pre-request script with special characters
const apiKey = ad.environment.get('api-key');
if (apiKey) {
ad.request.headers.set('X-API-Key', apiKey);
}
const timestamp = new Date().toISOString();
ad.request.headers.set('X-Timestamp', timestamp);
// Handle Unicode and special characters
ad.request.headers.set('X-Test-Header', '测试_тест_テスト_🚀');
ad.console.log('Complex pre-request script executed ✅');
''';
const complexPostScript = '''
// Post-response script with JSON parsing
try {
const data = ad.response.json();
if (data && data.access_token) {
ad.environment.set('token', data.access_token);
ad.console.log('Token extracted: ' + data.access_token.substring(0, 10) + '...');
}
// Handle different response codes
if (ad.response.status >= 400) {
ad.console.error('Request failed with status: ' + ad.response.status);
ad.environment.set('lastError', 'HTTP ' + ad.response.status);
} else {
ad.environment.unset('lastError');
}
} catch (e) {
ad.console.error('Script error: ' + e.message);
}
''';
notifier.update(
id: id,
preRequestScript: complexPreScript,
postRequestScript: complexPostScript,
);
final updatedRequest = notifier.getRequestModel(id);
expect(updatedRequest?.preRequestScript, equals(complexPreScript));
expect(updatedRequest?.postRequestScript, equals(complexPostScript));
});
test('should handle empty and null scripts gracefully', () {
final id = notifier.state!.entries.first.key;
// Test with empty strings
notifier.update(
id: id,
preRequestScript: '',
postRequestScript: '',
);
var updatedRequest = notifier.getRequestModel(id);
expect(updatedRequest?.preRequestScript, equals(''));
expect(updatedRequest?.postRequestScript, equals(''));
// Test with null values (should maintain existing values)
notifier.update(
id: id,
preRequestScript: 'ad.console.log("test");',
postRequestScript: 'ad.console.log("test");',
);
updatedRequest = notifier.getRequestModel(id);
expect(
updatedRequest?.preRequestScript, equals('ad.console.log("test");'));
expect(
updatedRequest?.postRequestScript, equals('ad.console.log("test");'));
});
test('should save and load scripts correctly', () async {
final id = notifier.state!.entries.first.key;
const preRequestScript = '''
ad.request.headers.set('Authorization', 'Bearer test-token');
ad.environment.set('requestStartTime', Date.now().toString());
''';
const postResponseScript = '''
const data = ad.response.json();
if (data && data.user_id) {
ad.environment.set('currentUserId', data.user_id);
}
''';
notifier.update(
id: id,
preRequestScript: preRequestScript,
postRequestScript: postResponseScript,
);
await notifier.saveData();
// Create new container and load data
late ProviderContainer newContainer;
try {
newContainer = ProviderContainer();
final newNotifier =
newContainer.read(collectionStateNotifierProvider.notifier);
// Give some time for the microtask in the constructor to complete
await Future.delayed(const Duration(milliseconds: 10));
final loadedRequest = newNotifier.getRequestModel(id);
expect(loadedRequest?.preRequestScript, equals(preRequestScript));
expect(loadedRequest?.postRequestScript, equals(postResponseScript));
} finally {
newContainer.dispose();
}
});
test('should handle scripts in addRequestModel', () {
const preRequestScript = 'ad.console.log("Added request pre-script");';
const postResponseScript = 'ad.console.log("Added request post-script");';
final httpRequestModel = HttpRequestModel(
method: HTTPVerb.post,
url: 'https://api.apidash.dev/data',
headers: const [
NameValueModel(name: 'Content-Type', value: 'application/json'),
],
body: '{"test": true}',
);
// Since addRequestModel takes HttpRequestModel, we'll test scripts through update
notifier.addRequestModel(httpRequestModel, name: 'Test Request');
final sequence = container.read(requestSequenceProvider);
final addedId = sequence.first;
notifier.update(
id: addedId,
preRequestScript: preRequestScript,
postRequestScript: postResponseScript,
);
final addedRequest = notifier.getRequestModel(addedId);
expect(addedRequest?.preRequestScript, equals(preRequestScript));
expect(addedRequest?.postRequestScript, equals(postResponseScript));
});
test('should handle scripts with various JavaScript syntax', () {
final id = notifier.state!.entries.first.key;
const advancedPreScript = r'''
// Advanced JavaScript features
const config = {
apiUrl: ad.environment.get('baseUrl') || 'https://api.apidash.dev/',
timeout: 5000,
retries: 3
};
// Arrow functions and template literals
const generateId = () => 'req_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
// Destructuring and modern syntax
const apiUrl = config.apiUrl;
const timeout = config.timeout;
ad.request.url.set(apiUrl + '/v1/users');
ad.request.headers.set('X-Request-ID', generateId());
ad.request.headers.set('X-Timeout', timeout.toString());
// Conditional logic
if (ad.environment.has('debugMode')) {
ad.request.headers.set('X-Debug', 'true');
ad.console.log('Debug mode enabled');
}
// Array operations
const requiredHeaders = ['Authorization', 'Content-Type'];
requiredHeaders.forEach(function(header) {
if (!ad.request.headers.has(header)) {
ad.console.warn('Missing required header: ' + header);
}
});
''';
const advancedPostScript = r'''
// Advanced response processing
try {
const response = ad.response.json();
// Object destructuring
const responseData = response ? response.data : null;
const meta = response ? response.meta : null;
const errors = response ? response.errors : null;
if (errors && Array.isArray(errors)) {
errors.forEach(function(error, index) {
ad.console.error('Error ' + (index + 1) + ': ' + error.message);
});
ad.environment.set('hasErrors', 'true');
} else {
ad.environment.unset('hasErrors');
}
// Handle pagination metadata
if (meta && meta.pagination) {
const page = meta.pagination.page;
const total = meta.pagination.total;
const hasNext = meta.pagination.hasNext;
ad.environment.set('currentPage', page.toString());
ad.environment.set('totalRecords', total.toString());
ad.environment.set('hasNextPage', hasNext.toString());
}
// Extract nested data
if (responseData && Array.isArray(responseData)) {
const activeItems = responseData.filter(function(item) {
return item.status === 'active';
});
ad.environment.set('activeItemCount', activeItems.length.toString());
// Store first active item ID if available
if (activeItems.length > 0) {
ad.environment.set('firstActiveId', activeItems[0].id);
}
}
} catch (parseError) {
ad.console.error('Failed to parse response JSON: ' + parseError.message);
ad.environment.set('parseError', parseError.message);
}
// Response timing analysis
const responseTime = ad.response.time;
if (responseTime) {
ad.environment.set('lastResponseTime', responseTime.toString());
if (responseTime > 2000) {
ad.console.warn('Slow response detected: ' + responseTime + 'ms');
ad.environment.set('slowResponse', 'true');
} else {
ad.environment.unset('slowResponse');
}
}
''';
notifier.update(
id: id,
preRequestScript: advancedPreScript,
postRequestScript: advancedPostScript,
);
final updatedRequest = notifier.getRequestModel(id);
expect(updatedRequest?.preRequestScript, equals(advancedPreScript));
expect(updatedRequest?.postRequestScript, equals(advancedPostScript));
});
test(
'should handle script updates without affecting other request properties',
() {
final id = notifier.state!.entries.first.key;
// First set up a complete request
notifier.update(
id: id,
method: HTTPVerb.post,
url: 'https://api.apidash.dev/test',
headers: const [
NameValueModel(name: 'Content-Type', value: 'application/json'),
NameValueModel(name: 'Accept', value: 'application/json'),
],
body: '{"test": "data"}',
name: 'Test Request',
description: 'A test request with scripts',
);
final beforeRequest = notifier.getRequestModel(id);
// Now update only scripts
const newPreScript = 'ad.console.log("Updated pre-script");';
const newPostScript = 'ad.console.log("Updated post-script");';
notifier.update(
id: id,
preRequestScript: newPreScript,
postRequestScript: newPostScript,
);
final afterRequest = notifier.getRequestModel(id);
// Verify scripts were updated
expect(afterRequest?.preRequestScript, equals(newPreScript));
expect(afterRequest?.postRequestScript, equals(newPostScript));
// Verify other properties were preserved
expect(afterRequest?.httpRequestModel?.method,
equals(beforeRequest?.httpRequestModel?.method));
expect(afterRequest?.httpRequestModel?.url,
equals(beforeRequest?.httpRequestModel?.url));
expect(afterRequest?.httpRequestModel?.headers,
equals(beforeRequest?.httpRequestModel?.headers));
expect(afterRequest?.httpRequestModel?.body,
equals(beforeRequest?.httpRequestModel?.body));
expect(afterRequest?.name, equals(beforeRequest?.name));
expect(afterRequest?.description, equals(beforeRequest?.description));
});
test(
'should not modify original state during script execution - only execution copy',
() {
final id = notifier.state!.entries.first.key;
const preRequestScript = r'''
// Script that modifies request properties
ad.request.headers.set('X-Script-Modified', 'true');
ad.request.headers.set('Authorization', 'Bearer script-token');
ad.request.url.set('https://api.apidash.dev/');
ad.request.params.set('scriptParam', 'scriptValue');
ad.environment.set('scriptExecuted', 'true');
ad.console.log('Pre-request script executed and modified request');
''';
// Set up initial request properties
notifier.update(
id: id,
method: HTTPVerb.get,
url: 'https://api.apidash.dev/api',
headers: const [
NameValueModel(name: 'Content-Type', value: 'application/json'),
NameValueModel(name: 'Accept', value: 'application/json'),
],
params: const [
NameValueModel(name: 'originalParam', value: 'originalValue'),
],
preRequestScript: preRequestScript,
);
// Capture the original state before script execution simulation
final originalRequest = notifier.getRequestModel(id);
final originalHttpRequestModel = originalRequest!.httpRequestModel!;
// Test the script execution isolation by simulating the copyWith pattern used in sendRequest
final executionRequestModel = originalRequest.copyWith();
// Verify that the execution copy is separate from original
expect(executionRequestModel.id, equals(originalRequest.id));
expect(executionRequestModel.httpRequestModel?.url,
equals(originalRequest.httpRequestModel?.url));
expect(executionRequestModel.httpRequestModel?.headers,
equals(originalRequest.httpRequestModel?.headers));
expect(executionRequestModel.httpRequestModel?.params,
equals(originalRequest.httpRequestModel?.params));
// Simulate script modifications on the execution copy
final modifiedExecutionModel = executionRequestModel.copyWith(
httpRequestModel: executionRequestModel.httpRequestModel?.copyWith(
url: 'https://api.apidash.dev/',
headers: [
...originalHttpRequestModel.headers ?? [],
const NameValueModel(name: 'X-Script-Modified', value: 'true'),
const NameValueModel(
name: 'Authorization', value: 'Bearer script-token'),
],
params: [
...originalHttpRequestModel.params ?? [],
const NameValueModel(name: 'scriptParam', value: 'scriptValue'),
],
),
);
// Verify the execution copy has been modified
expect(modifiedExecutionModel.httpRequestModel?.url,
equals('https://api.apidash.dev/'));
expect(
modifiedExecutionModel.httpRequestModel?.headers?.length, equals(4));
final hasScriptModifiedHeader = modifiedExecutionModel
.httpRequestModel?.headers
?.any((header) => header.name == 'X-Script-Modified') ??
false;
expect(hasScriptModifiedHeader, isTrue);
final hasAuthHeader = modifiedExecutionModel.httpRequestModel?.headers
?.any((header) => header.name == 'Authorization') ??
false;
expect(hasAuthHeader, isTrue);
final hasScriptParam = modifiedExecutionModel.httpRequestModel?.params
?.any((param) => param.name == 'scriptParam') ??
false;
expect(hasScriptParam, isTrue);
// Verify that the original request in the state remains completely unchanged
final currentRequest = notifier.getRequestModel(id);
expect(currentRequest?.httpRequestModel?.url,
equals('https://api.apidash.dev/api'));
expect(currentRequest?.httpRequestModel?.headers?.length, equals(2));
expect(currentRequest?.httpRequestModel?.headers?[0].name,
equals('Content-Type'));
expect(currentRequest?.httpRequestModel?.headers?[0].value,
equals('application/json'));
expect(
currentRequest?.httpRequestModel?.headers?[1].name, equals('Accept'));
expect(currentRequest?.httpRequestModel?.headers?[1].value,
equals('application/json'));
expect(currentRequest?.httpRequestModel?.params?.length, equals(1));
expect(currentRequest?.httpRequestModel?.params?[0].name,
equals('originalParam'));
expect(currentRequest?.httpRequestModel?.params?[0].value,
equals('originalValue'));
// Verify no script-modified headers are present in the original state
final hasScriptModifiedHeaderInOriginal = currentRequest
?.httpRequestModel?.headers
?.any((header) => header.name == 'X-Script-Modified') ??
false;
expect(hasScriptModifiedHeaderInOriginal, isFalse);
final hasAuthHeaderInOriginal = currentRequest?.httpRequestModel?.headers
?.any((header) => header.name == 'Authorization') ??
false;
expect(hasAuthHeaderInOriginal, isFalse);
// Verify no script-modified params are present in the original state
final hasScriptParamInOriginal = currentRequest?.httpRequestModel?.params
?.any((param) => param.name == 'scriptParam') ??
false;
expect(hasScriptParamInOriginal, isFalse);
// Verify the script is preserved in the original
expect(currentRequest?.preRequestScript, equals(preRequestScript));
});
tearDown(() {
container.dispose();
});
});
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,341 @@
import 'package:flutter/material.dart';
import 'package:flutter_highlight/themes/xcode.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_code_editor/flutter_code_editor.dart';
import 'package:flutter_highlight/themes/monokai.dart';
import 'package:highlight/languages/javascript.dart';
import 'package:highlight/languages/json.dart';
import 'package:apidash_design_system/apidash_design_system.dart';
import 'package:apidash/widgets/editor_code.dart';
import '../test_consts.dart';
void main() {
group('CodeEditor Widget Tests', () {
late CodeController testController;
setUp(() {
testController = CodeController(
text: 'print("Hello World")',
language: javascript,
);
});
testWidgets('renders CodeEditor with default parameters', (tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
),
),
),
);
expect(find.byType(CodeEditor), findsOneWidget);
expect(find.byType(CodeField), findsOneWidget);
expect(find.byType(CodeTheme), findsOneWidget);
});
testWidgets('renders CodeEditor in read-only mode', (tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor ReadOnly Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
readOnly: true,
),
),
),
);
expect(find.byType(CodeEditor), findsOneWidget);
// Verify the CodeField is in read-only mode
final codeField = tester.widget<CodeField>(find.byType(CodeField));
expect(codeField.readOnly, isTrue);
});
testWidgets('renders CodeEditor in editable mode by default',
(tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Editable Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
),
),
),
);
expect(find.byType(CodeEditor), findsOneWidget);
// Verify the CodeField is editable by default
final codeField = tester.widget<CodeField>(find.byType(CodeField));
expect(codeField.readOnly, isFalse);
});
testWidgets('CodeEditor has correct decoration properties', (tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Decoration Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
),
),
),
);
final codeField = tester.widget<CodeField>(find.byType(CodeField));
final decoration = codeField.decoration as BoxDecoration;
// Check border radius
expect(decoration.borderRadius, equals(kBorderRadius8));
// Check that decoration has a border and color
expect(decoration.border, isNotNull);
expect(decoration.color, isNotNull);
});
testWidgets('CodeEditor has correct gutter style properties',
(tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Gutter Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
),
),
),
);
final codeField = tester.widget<CodeField>(find.byType(CodeField));
final gutterStyle = codeField.gutterStyle;
expect(gutterStyle.width, equals(0));
expect(gutterStyle.margin, equals(2));
expect(gutterStyle.textAlign, equals(TextAlign.left));
expect(gutterStyle.showFoldingHandles, isFalse);
expect(gutterStyle.showLineNumbers, isFalse);
});
testWidgets('CodeEditor has correct smart typing settings', (tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Smart Typing Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
),
),
),
);
final codeField = tester.widget<CodeField>(find.byType(CodeField));
expect(codeField.smartDashesType, equals(SmartDashesType.enabled));
expect(codeField.smartQuotesType, equals(SmartQuotesType.enabled));
});
testWidgets('CodeEditor expands to fill available space', (tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Expand Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
),
),
),
);
final codeField = tester.widget<CodeField>(find.byType(CodeField));
expect(codeField.expands, isTrue);
});
testWidgets('CodeEditor uses correct text style with theme font size',
(tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Text Style Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
),
),
),
);
final codeField = tester.widget<CodeField>(find.byType(CodeField));
final textStyle = codeField.textStyle;
// Verify that text style is based on kCodeStyle
expect(textStyle?.fontFamily, equals(kCodeStyle.fontFamily));
// Verify that font size is taken from theme
final themeContext = tester.element(find.byType(CodeEditor));
final expectedFontSize =
Theme.of(themeContext).textTheme.bodyMedium?.fontSize;
expect(textStyle?.fontSize, equals(expectedFontSize));
});
testWidgets('CodeEditor uses theme colors for background and cursor',
(tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Colors Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
),
),
),
);
final codeField = tester.widget<CodeField>(find.byType(CodeField));
final themeContext = tester.element(find.byType(CodeEditor));
final colorScheme = Theme.of(themeContext).colorScheme;
// Verify background color
expect(codeField.background, equals(colorScheme.surfaceContainerLowest));
// Verify cursor color
expect(codeField.cursorColor, equals(colorScheme.primary));
// Verify decoration background color
final decoration = codeField.decoration as BoxDecoration;
expect(decoration.color, equals(colorScheme.surfaceContainerLowest));
});
testWidgets('CodeEditor with custom controller content', (tester) async {
final customController = CodeController(
text: '{\n "key": "value",\n "number": 42\n}',
language: json,
);
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Custom Content Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: customController,
),
),
),
);
expect(find.byType(CodeEditor), findsOneWidget);
// Verify the controller is properly set
final codeField = tester.widget<CodeField>(find.byType(CodeField));
expect(codeField.controller, equals(customController));
expect(codeField.controller.text, contains('"key": "value"'));
});
testWidgets('CodeEditor with all parameters set', (tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor All Parameters Test',
theme: kThemeDataDark,
home: Scaffold(
body: CodeEditor(
controller: testController,
readOnly: true,
isDark: true,
),
),
),
);
expect(find.byType(CodeEditor), findsOneWidget);
final codeField = tester.widget<CodeField>(find.byType(CodeField));
final codeTheme = tester.widget<CodeTheme>(find.byType(CodeTheme));
// Verify all parameters are applied
expect(codeField.readOnly, isTrue);
expect(codeTheme.data?.styles, equals(monokaiTheme));
expect(codeField.controller, equals(testController));
});
testWidgets('CodeEditor widget key is properly set', (tester) async {
const testKey = Key('test-code-editor');
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Key Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
key: testKey,
controller: testController,
),
),
),
);
expect(find.byKey(testKey), findsOneWidget);
expect(find.byType(CodeEditor), findsOneWidget);
});
testWidgets('renders CodeEditor with light theme (isDark: false)',
(tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Light Theme Test',
theme: kThemeDataLight,
home: Scaffold(
body: CodeEditor(
controller: testController,
isDark: false,
),
),
),
);
expect(find.byType(CodeEditor), findsOneWidget);
expect(find.byType(CodeField), findsOneWidget);
// Verify the CodeTheme is using light theme (xcode)
final codeTheme = tester.widget<CodeTheme>(find.byType(CodeTheme));
expect(codeTheme.data?.styles, equals(xcodeTheme));
});
testWidgets('renders CodeEditor with dark theme (isDark: true)',
(tester) async {
await tester.pumpWidget(
MaterialApp(
title: 'CodeEditor Dark Theme Test',
theme: kThemeDataDark,
home: Scaffold(
body: CodeEditor(
controller: testController,
isDark: true,
),
),
),
);
expect(find.byType(CodeEditor), findsOneWidget);
expect(find.byType(CodeField), findsOneWidget);
// Verify the CodeTheme is using dark theme (monokai)
final codeTheme = tester.widget<CodeTheme>(find.byType(CodeTheme));
expect(codeTheme.data?.styles, equals(monokaiTheme));
});
});
}