| name | gas-fakes-dev |
| description | Develop, implement, and test the 'gas-fakes' project, emulating ALL Google Apps Script (GAS) functionality using Node.js and Google APIs. |
| tags | ["nodejs","google-apps-script","google-cloud-api","testing","mock","simulation"] |
| version | 2.0.0 |
Summary
This skill enables the agent to act as a Senior Expert proficient in Node.js, Google Cloud, and Shell Scripting to assist in the development of the gas-fakes project.
The ultimate objective is to emulate the behavior of live Google Apps Script exactly by mapping classes and methods to their fake equivalents. This allows Apps Script to run anywhere Node runs.
This is achieved using a worker mechanism to handle the conversion from synchronous (Apps Script) to asynchronous (Google APIs) operations, returning the results synchronously. Ultimately, all Apps Script classes and methods will be available via gas-fakes. For a deep dive into this mechanism, see the Sync-to-Async Bridge Guide.
Usage
- When you need to implement or modify mock functionality for specific GAS classes or methods.
- When creating logic that reproduces GAS behavior using Google APIs and the worker mechanism.
- When adding new service classes to fit the existing
gas-fakes project structure.
- When creating test scripts and registering them for local execution within the
test/ directory.
- When executing generated Apps Script files locally.
- When technical advice or debugging assistance based on GAS specifications is required.
Configuration
gas-fakes relies on an .env file (maintained by gas-fakes init and auth) to properly authenticate and run.
Authentication Methods
- DWD (Domain Wide Delegation) - Preferred: Uses a service account to impersonate a user logged into gcloud. The service account name must be specified in the
.env file. This is required if restricted/sensitive scopes are needed, or if running gas-fakes on Google Cloud Run.
- ADC (Application Default Credentials): If no
.env file is provided, gas-fakes falls back to ADC. This is usually fine for local development as standard cloud_platform and drive scopes are automatically assigned during auth.
Ensure your .env is properly loaded (e.g., using node --env-file <env-file> or gas-fakes -e <env-file>) to ensure DWD is used when necessary.
TEST_SPREADSHEET_ID: (Optional) Spreadsheet ID for real-environment testing.
Workflow
1. Context, Specification, and Dependency Check
Before starting implementation, you must understand the full scope and style of the project.
-
Restricted Directories:
- NEVER modify any files located in the
progress directory during the development of gas-fakes. This directory is strictly off-limits.
-
Mandatory Existence Verification:
When adding or updating ANY class or method, you must ALWAYS use the workspace-developer MCP server (if available) or search official documentation to verify the existence and specification of the target and ALL related classes/methods.
- NEVER create classes or methods that do not exist in the actual Google Apps Script environment.
- Do not guess. Confirm exact names, parameter structures, and return types.
- Example: If implementing
Sheet.getCharts(), check what object it returns (EmbeddedChart vs Chart) and verify the methods available on that returned object.
-
Strict Enum Verification:
Do not invent Enums. Before using or creating an Enum, verify if it actually exists in Google Apps Script.
- Note on
ChartType: In Google Apps Script, ChartType is a property of the Charts service (Charts.ChartType), not SpreadsheetApp.
-
Reference Existing Code:
Check the src and test directories to understand the existing coding style and architecture. Apply these patterns to new classes and methods.
-
Identify Dependencies:
Identify and implement all related classes and methods required for the target feature. (e.g., if newChart() returns EmbeddedChartBuilder, verify/implement that builder class too).
2. Scaffolding
Do not create service files manually. Use the provided helper script.
3. Implementation
Generate code based on Node.js best practices, adhering to these rules to maintain environmental consistency with live Apps Script:
-
Comprehensive Implementation: Implement the target feature and its dependencies together.
-
Cross-Environment Compatibility: Scripts must be designed to run on both Node.js (local) and GAS Script Editor with identical results.
-
toString() Accuracy: The toString() method must return the exact GAS class name or specific string output (e.g., "Sheet" or "[Document: ...]"). Pay extreme attention to whitespace; GAS output can contain double spaces (e.g., after a colon).
-
Dynamic Resources and Caching Pattern:
- The
__resource property: Always access the underlying API state via the dynamic __resource getter (tracing back to the parent element or a synchronized cache).
- Stale State Prevention: NEVER store API resources directly in class instance variables. They will become stale when the cache is cleared.
- Cache Invalidation: Every time a destructive API call is made, the cache is cleared. Dynamically accessing
__resource ensures you get the most up-to-date state from the API or the fresh cache.
-
Implementation Patterns:
- Use
signatureArgs or is.* utilities.
- Construct the request object.
- Execute via
this.__batchUpdate (or helper).
- Return
this for chaining.
-
Coding Patterns:
- Naming: Internal implementation classes should be prefixed with
Fake (e.g., FakeSheet, FakeEmbeddedChart).
- Lazy Loading: New top-level services must be registered using the
lazyLoaderApp pattern in their respective app.js to ensure they are only instantiated when accessed.
- Singleton Pattern: Service entry points usually export a "maker" function (e.g.,
newFakeSpreadsheetApp) that return the singleton instance.
-
Specific Technical Nuances:
- Sync-to-Async Bridge: Always use the worker bridge for external API calls to maintain synchronous Apps Script behavior. Follow the pattern:
Fake Class -> Syncit (fx*) -> callSync -> Worker Loop -> sx* Function -> sxRetry. See detailed guide for implementation steps.
- Charts: When retrieving a chart's title, use
getOptions().get("title") instead of internal specs.
- EmbeddedChart: To get the type of an existing chart, use
modify().getChartType() instead of a non-existent getType() method.
- GridRange to FakeRange Conversion: When mapping an API
GridRange to a FakeSheetRange:
- Indices in the API are 0-indexed and the end index is exclusive.
- GAS methods (like
getRange(row, col, numRows, numCols)) use 1-indexed start positions and row/column counts.
- If
endRowIndex or endColumnIndex is undefined in the API response, it means the range extends to the boundary of the sheet. Use sheet.getMaxRows() and sheet.getMaxColumns() as fallbacks to calculate numRows and numCols.
- ContainerInfo: This class is used by
EmbeddedChart, Slicer, and Drawing.
- Map
getAnchorRow() and getAnchorColumn() to 0-indexed API fields anchorCell.rowIndex + 1 and anchorCell.columnIndex + 1.
- Map
getOffsetX() and getOffsetY() directly to offsetXPixels and offsetYPixels.
- XmlService:
Element.getName() returns the local name (no prefix).
Document.toString() output is very specific: [Document: No DOCTYPE declaration, Root is [Element: <rootName/>]] (note the double space after Document:).
- Namespace-aware methods (like
getChild(name, namespace)) require mapping prefixes and URIs correctly.
4. Testing
You must ensure every implementation is verified by tests that precisely emulate Google Apps Script behavior.
-
Mandatory Feature Coverage:
- Every new class or method MUST have a corresponding test.
- If you implement multiple methods, create a test script that exercises all of them.
- Test only implemented features; do not include placeholders for future work.
-
Edge Case Capturing:
- Capture and verify boundary conditions, invalid inputs, and error states.
- Use
t.rxMatch(t.threw(() => ...).message, /regex/) to verify that methods throw expected GAS error messages when given invalid arguments.
- Test with
null, undefined, empty strings, and out-of-bounds values where applicable to ensure robust emulation.
-
GAS Compatibility Requirement:
- Test logic (inside
unit.section) must be compatible with the Google Apps Script script editor.
- Avoid Node.js-specific modules (e.g.,
fs, path) inside the test logic.
- Use
ScriptApp.isFake or xxxApp.isFake to toggle environment-specific logging or assertions.
-
Test Script Structure:
- Imports: standard test scripts import
@mcpher/gas-fakes, @sindresorhus/is, and helpers from ./testinit.js and ./testassist.js.
- Export Pattern: Export a named function (e.g.,
export const testService = (pack) => { ... }) to allow integration into the main test suite.
- Execution Hook: Always include
wrapupTest(testService); at the end of the file for standalone execution.
- Sections: Use
unit.section("description", (t) => { ... }) to group tests.
-
Resource Lifecycle and Cleanup:
- The
toTrash pattern: Maintain a toTrash array within your test function. Push any created resources (files, folders, sheets) into this array.
- Automatic Cleanup: Use
trasher(toTrash) at the end of the test function (usually triggered if fixes.CLEAN is true) to ensure the test environment remains pristine.
-
Naming Convention:
- Google Sheets:
testsheets{class name}.js (e.g., testsheetsrange.js)
- Google Docs:
testdocs{class name}.js
- Google Slides:
testslides{class name}.js
- General/Other:
test{service}{class name}.js
-
Registration:
- Create the file in
test/.
- Add to
test/test.js.
- Add a script entry in
test/package.json.
-
Execution:
[!IMPORTANT]
Run tests from the test/ directory.
cd test && node test{filename}.js execute (or npm run <script-name>).
-
Clasp Verification:
Use testongas/test/ to verify against a real GAS project via clasp.
5. Executing Generated Scripts
You can execute any generated Apps Script file using gas-fakes in a local sandbox.
6. Refinement & Continuous Evolution (Self-Updating SKILL)
To ensure the gas-fakes project and this SKILL continuously evolve and improve efficiently, you MUST actively refine and update the SKILL definition (SKILL.md) and its associated resources based on the outcomes of your development processes.
6.1 Skill Audit Criteria
At the conclusion of every task, perform a "Self-Audit" by answering:
- New Pattern? Did I implement a new mapping logic (e.g., API-to-GAS index shifts) or a reusable architectural pattern?
- Missing Nuance? Did I encounter a technical detail (like a specific
toString() format or Enum location) that wasn't documented?
- Corrected Assumption? Did a test failure or user hint reveal that a rule in this SKILL was incomplete or incorrect?
- New Service? Did I add a new class that requires a dedicated section in the "Technical Nuances" list?
6.2 Prompt for Update Mandate
If any criteria in the "Skill Audit" are met, you MUST:
- Analyze the New Knowledge: Determine what core knowledge, rule, constraint, or pattern was derived from the success or resolution.
- Identify the Change: Specifically state what needs to be added, modified, or deleted in
SKILL.md.
- Propose the Edit: Present the specific Markdown block intended for the update.
- Ask for Confirmation: Explicitly ask the user: "Based on this task, I recommend updating the SKILL.md with the following [nuance/pattern]. Should I apply this change?"
- Update Associated Assets: If the new knowledge involves a reusable code structure or boilerplate, add or update files in the
examples/, resources/, or scripts/ directories to reflect the new best practice.
7. Delivery
- Output: Full content of modified or newly created files (Service class, Node.js test, etc.).
- Skill Audit: Provide a brief (1-2 sentence) summary of your Self-Audit results.
- Update Prompt: If any audit criteria were met, issue the "Prompt for Update" as defined in section 6.2.
- Finality: Conclude with a concise summary of the task results.