Summary
This skill enables the agent to assist in the development of the gas-fakes project. The primary objective is to emulate Google Apps Script (GAS) behavior using Node.js and Google APIs, allowing Apps Script code to run in a local Node.js environment.
Usage
- When you need to implement fake/mock functionality for GAS classes or methods.
- When creating test scripts to verify the implemented functionalities.
- When assisting a human developer with Node.js and Google APIs integration.
Workflow
0. Local Model Consultation (Hybrid Hierarchical Delegation)
Before drafting implementation plans, code, tests, refactoring, debugging, analyzing logs, or drafting documentation, Gemini (the Strategic Planner) must first gather all relevant file context, decompose the request into structured atomic sub-tasks, and call the local model (via the omlx:query_local_model tool with the prompt parameter) to generate precise code implementations, detailed tests, refactored components, bug fixes, or documentation updates.
1. Context and Specification Check
Before implementing, verify the specifications of the target Google Apps Script classes and methods. Ensure that the functionality you are about to build aligns with real GAS behavior.
2. Implementation & Focused Execution (CRITICAL DELEGATION GATE)
[!IMPORTANT] ZERO-TOLERANCE DELEGATION GATE You are FORBIDDEN from using
write_fileorreplaceto implement logic, write tests, perform refactoring, diagnose/fix debug errors, or draft documentation yourself. MANDATORY SEQUENCE:
- Gather context (Research).
- CALL
omlx/query_local_modelwith a comprehensive prompt containing specific constraints.- Review and synthesize the output.
- Apply changes to files (e.g., in
src/,test/, etc.).EXCEPTION: This mandate only applies if the local model is available and its use has not been explicitly forbidden by the user. If unavailable or forbidden, you may proceed with the tasks using your own weights, but you MUST document the reason in your
update_topic.You MUST explicitly state "Delegating logic generation/task to local Gemma model" in your
update_topicsummary when transitioning to execution.
- The planner (Gemini) reviews the local model's output code, refines it, and applies it to the
src/directory. - Ensure the code runs correctly in the Node.js environment.
3. Testing
You must verify your implementation by writing and executing test scripts.
- Always Add Tests for New Methods: Whenever you implement a new method, class, or service, you MUST immediately add corresponding tests in the
test/directory to prove your implementation works and maintains parity. Never add code without adding tests. - Network Call Safety: All network-based commands (e.g.,
curl) MUST include an aggressive timeout (e.g.,--max-time 5or--connect-timeout 2) to prevent processes from hanging and accruing costs in the event of a server deadlock. - Temporary/Exploratory Scripts: If you need to create temporary scripts to test logic, explore APIs, or run isolated experiments outside the formal test suite, you MUST create them in the
gasmess/gemini/directory (e.g.,gasmess/gemini/test_something.js). This folder is excluded from version control and prevents cluttering the repository root. - Place your formal test scripts in the
test/directory. - Execute the tests to ensure there are no errors and the behavior matches expectations.
- Full instructions on test and other workflows are in ../../workflows. Be sure to read the relevant workflow file before starting any task.
4. Test Registration and Suite Integrity (CRITICAL)
Whenever you create a new test script (e.g., test/testnewfeature.js) or significantly modify an existing one, you MUST follow the add-new-test.md workflow exactly:
- Create the file in the
test/directory. - Register in
test/test.js: Add theimportstatement and the test call withintestFakes(). - Register in
test/package.json: Add a corresponding entry to the"scripts"section (e.g.,"testnewfeature": "node testnewfeature.js execute").
- Workflow Compliance: At the beginning of EVERY task involving testing or implementation, you MUST consult the
.agents/workflows/directory (specificallytest.mdandadd-new-test.md) to ensure you are following the latest project-specific procedures.
5. Holistic/Targeted Skill Evolution (Self-Updating SKILL)
[CRITICAL INSTRUCTION]
The gas-fakes project is complex, and bridging Node.js with GAS involves many hidden constraints, specific architectural patterns, and potential errors. You are required to continuously learn and autonomously evolve this SKILL.
- Trigger: Whenever you encounter an error during implementation or testing, or when you receive correction feedback/prompts from the human developer.
- Action: You MUST extract the lessons learned from the failure and recovery process. Identify the underlying rules, technical constraints, or coding patterns that caused the issue.
- Update: Immediately update this
SKILL.mdfile (by adding, deleting, or modifying content) to document the newly acquired knowledge. If necessary, also create or update sample scripts, helper templates, or explanatory Markdown files in the project. - Goal: Transform your localized, temporary learnings into permanent, universally readable knowledge to prevent repeating the same mistakes and to handle the complexities of the project autonomously.
- CREDENTIALS: Never commit actual credentials or keys you might discover in the .env file to the repository nor to the SKILL.md file.
Documented Knowledge & Lessons Learned
Apps Script JDBC to Google Cloud SQL PostgreSQL
- Connection Method: You CANNOT use
Jdbc.getCloudSqlConnection()for PostgreSQL in Apps Script; it only works for MySQL. You MUST use standardJdbc.getConnection(). - IP Whitelisting: Because Live Apps Script runs on dynamic Google IPs, you must whitelist Google's API IP ranges (fetched from
https://www.gstatic.com/ipranges/goog.json) in your Cloud SQL instance's Authorized Networks to allow connection. - Connection String Formatting: Apps Script's
Jdbc.getConnection()has strict requirements for Postgres when hosted on Google Cloud:- You CANNOT use
ssl=trueas a query parameter (e.g.,jdbc:postgresql://<IP>:<PORT>/<DB>?ssl=true). The Java driver on Apps Script throwsThe following connection properties are unsupported: ssl. - Do not embed url-encoded credentials directly into the URL. Instead, use the 3-argument signature:
Jdbc.getConnection("jdbc:postgresql://<IP>:<PORT>/<DB>", rawUser, rawPass).
- You CANNOT use
Apps Script JDBC to Google Cloud SQL MySQL
- Connection Method: You CAN use
Jdbc.getCloudSqlConnection(url, user, password)for MySQL on Google Cloud using the specific protocol formatjdbc:google:mysql://[INSTANCE_CONNECTION_NAME]/[DATABASE_NAME]. - Local Node.js Emulation: The Node
mysql2driver cannot directly resolve Google Cloud SQL instance names containing colons (e.g.project:region:instance). To emulateJdbc.getCloudSqlConnectionlocally without the Cloud SQL Auth Proxy, you must:- Extract the instance connection name.
- Use the
gcloud sql instances describe [INSTANCE_NAME]command to dynamically resolve the instance's public IP address. - Swap the instance name for the resolved IP address in the connection string.
- Ensure your local machine's IP address is authorized on the Cloud SQL instance.
- Node URL Parsing: Avoid passing connection strings with instance names (colons) directly into standard Node.js URL parsers (like
new URL()), as it will fail. Ensure the string is formatted as[protocol://]user:pass@host/dbor parse the parameters manually.
Apps Script JDBC Data Types & Results
- BigDecimal Handling:
JdbcResultSet.getBigDecimal()returns aJdbcBigDecimalobject on live GAS. This is a Java proxy that may NOT expose standard Java methods likedoubleValue(). To get a numeric value safely across all platforms, useNumber(val)orparseFloat(val.toString()). - Column Resolution:
JdbcResultSetmethods (e.g.,getString()) support both 1-indexed integers and string column labels. Ensure the fake implementation resolves both usingfindColumn.
JDBC Driver Compatibility (Live GAS)
- Semicolons in Prepared Statements: Avoid trailing semicolons (
;) in strings passed toprepareStatement. Some drivers (e.g., MySQL on GAS) may fail to recognize?placeholders if a semicolon is present. - Connection Methods:
- MySQL (Google Cloud): MUST use
Jdbc.getCloudSqlConnection. - MySQL (Other/External): MUST use
Jdbc.getConnection. - PostgreSQL (All): MUST use
Jdbc.getConnection.
- MySQL (Google Cloud): MUST use
- Parameter Index Errors (MySQL 8+): For external MySQL databases (e.g., Aiven), the
prepareStatementmethod may fail withParameter index out of range (1 > 0)because the older GAS driver cannot parse placeholders in modern MySQL 8+ protocols.- Workaround: Implement a
try/catchfallback to standardStatement.execute()with manually escaped values ifprepareStatementfails for MySQL backends.
- Workaround: Implement a
Apps Script Constraints & Web APIs
- Unavailable Web APIs: The GAS V8 runtime DOES NOT support many standard Web APIs, including
TextDecoder,TextEncoder,fetch,setTimeout, andReadableStream. - String/Byte Conversion: To convert a byte array to a string portably, use:
const str = Utilities.newBlob(bytes).getDataAsString(); - IP Whitelisting: Because Live Apps Script runs on dynamic Google IPs, you must whitelist Google's API IP ranges (fetched from
https://www.gstatic.com/ipranges/goog.json) in your Cloud SQL instance's Authorized Networks to allow connection. - Portability Rule: When writing tests designed to run on both platforms, you MUST guard access to fake-only properties using
if (ScriptApp.isFake). - Minimization Strategy (CRITICAL): Minimize the use of
if (ScriptApp.isFake)blocks. Whenever possible, verify behaviors and expected return values using the Public API.- Example: Instead of checking
__fakeObjectType === 'JdbcBlob', simply callblob.length()orblob.getBytes(). If these work, the object is implicitly of the correct type.
- Example: Instead of checking
- Why?: Extensive use of
if (ScriptApp.isFake)makes the test suite harder to maintain and reduces confidence that the same test is actually verifying the same behavior on both platforms.
GAS JDBC Runtime Constraints (Critical for Live Tests)
getBlob()requires an OID large object column — not BYTEA: Callingrs.getBlob(n)on aTEXTorBYTEAcolumn throws"Bad value for type long : <value>"because the PostgreSQL JDBC driver'sgetBlob()internally callsgetLong()to retrieve a PostgreSQL large object OID frompg_largeobject. For inline binary data, usegetBytes()/getBinaryStream()instead. MySQL'sBLOBtype maps directly and works withgetBlob(). In practice: never testgetBlob()against a PostgreSQL/CockroachDB backend in a parity test.createStatement()returnsFORWARD_ONLY: Plainconn.createStatement()returns a forward-only cursor. Navigation methodslast(),first(),absolute(),relative(),previous(),beforeFirst(),afterLast()all throw"Operation requires a scrollable ResultSet". Useconn.createStatement(1004, 1007)(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY) to get a scrollable cursor. In the fake, these parameters are accepted but advisory — results are already buffered.getFloat()is 32-bit: GASrs.getFloat()returns an IEEE 754 single-precision float.1.1becomes1.100000023841858. Always compare withMath.fround(expected). The fake appliesMath.fround()accordingly.getDouble()is 64-bit: Unlike the above,rs.getDouble()returns a full 64-bit double.
Test Suite Execution & Architecture (CRITICAL)
[!DANGER] NEVER RUN TESTS FROM THE ROOT DIRECTORY. All test commands MUST be run from within the
test/directory. Failure to do so will result in.envvariables not being loaded and tests failing silently or with obscure errors. CORRECT:cd test && node testsheetsdeveloper.js executeINCORRECT:node test/testsheetsdeveloper.js
- Directory Requirement: You MUST run all test commands from within the
test/directory. - Execution Flag: When running a test file directly with
node, you MUST append theexecuteargument (e.g.,node testsomething.js execute). - Individual Test Execution (Efficiency): Do NOT run the full test suite (
node test.jsornpm test) unless explicitly requested or necessary for final verification. Instead, run only the specific test file you are working on. This saves significant time and avoids API rate limits. - Dependency Aliasing (CRITICAL): The
test/package.jsonresolves"@mcpher/gas-fakes": "file:.."as a local symlink. Because of this,import '@mcpher/gas-fakes'inside thetest/directory automatically pulls in your local, uncommitted changes fromsrc/. NEVER rewrite test imports to relative paths likeimport '../src/index.js'. Doing so breaks the test suite's isolation from module-level side effects and ignores the intended aliasing architecture. - Worker Thread Error Re-hydration:
gas-fakesuses a background worker (src/support/workersync/worker.js) to make async API calls synchronous. If an API request fails, the worker catches the error, serializes it (often as a nested JSON string likeerr.response.data.error), and writes it to aSharedArrayBuffer.- To properly intercept these errors in tests using
@mcpher/unit'st.threw, you must ensure that thesynchronizer.jssuccessfully extracts the underlying error message and explicitly assigns it when re-hydrating theErrorobject on the main thread (otherwiseerr.messagemight beundefined).
- To properly intercept these errors in tests using
Apps Script API Nuances & Discoveries
- DeveloperMetadata Location (Sheets API): When updating or creating
DeveloperMetadatausing the Sheets API (batchUpdate), the API considers thelocation.locationTypeproperty to be read-only. You must supply the boundary object (dimensionRange,spreadsheet, orsheetId), but you MUST NOT supply the stringlocationType. Including it will cause a 400 Bad Request. - Drive API Exports (
file.getAs): Live Apps Script allows developers to callfile.getAs('application/pdf')on plain text files. However, the standard Google Drive REST API (drive.files.export) strictly only supports exporting Google Docs Editor files (Docs, Sheets, Slides).- To maintain parity with Apps Script,
gas-fakesimplements a two-step conversion workaround under the hood: when an export fails due to thefileNotExportablelimitation,gas-fakestemporarily copies the file into a Google Doc (or Sheet/Slide), exports the temporary file to the requested format, and then trashes the temporary file. This ensuresfile.getAs('application/pdf')succeeds transparently for text and CSV files just like it does in live Apps Script.
- To maintain parity with Apps Script,
- Drive API Permissions & Roles Parity: In
DriveApp, functions likegetViewers()andgetEditors()do NOT cascade or inherit roles. A user is only returned in the specific group they are assigned to via the Drive API.ownerrole -> returned bygetOwner()writerrole -> returned bygetEditors()readerandcommenterroles -> returned bygetViewers()- There is no need to manually append "owners" or "writers" to the viewers list. Live Apps Script maintains strict segregation between these categories based on their primary role.
- Null IDs in Advanced Services: Unlike standard
DriveApp(which immediately throws anInvalid argument: iderror if passednullorundefined), Live Apps Script Advanced Services (likeDrive.Files.get(null)) might silently fail or not throw an easily catchable exception. Do not write parity tests that expect Advanced Services to consistently throw specific errors fornullparameters.
GmailApp & GmailMessage Limitations
- Missing Methods:
gas-fakesimplementation ofGmailMessage(i.e.FakeGmailMessage) does not natively support all methods found in Apps Script (e.g.,getSubject(),getDate(),getSnippet(),getFrom(),getTo()). - Workaround/Implementation: When implementing these missing methods, you must extract the information from the raw Gmail API resource (e.g., parsing the
payload.headersarray to find the 'Subject' or 'Date'). - Message Retrieval:
GmailThread.getMessages()is not implemented directly on theFakeGmailThreadobject. You should useGmailApp.getMessagesForThread(thread)instead.
Google Cloud CLI & Eventual Consistency
- IAM Propagation Delay: When creating a new service account or applying IAM permissions via
gcloud, Google Cloud IAM may take several seconds to propagate changes. Subsequent commands referencing the new entity may fail with "not found" errors if executed too quickly. - Retry Mechanism: Always implement a retry loop (e.g., 5 retries with 5s delay) for
gcloud iamcommands that depend on recently created resources. A simple busy-wait orexecSyncto a sleep command can be used in a synchronous CLI environment to ensure portability. - Portability: For cross-platform sync sleep in Node.js, a busy-wait loop (
while (Date.now() - start < delay)) is often more reliable than depending on OS-specificsleeportimeoutcommands when running inside a CLI tool.
Gmail API & Advanced Service Nuances
- Advanced Service Method Hand-Coding: The Advanced Services in
gas-fakes(likeFakeAdvGmailMessages) do not automatically expose all methods from the underlyinggoogleapispackage. If you need a method likegmail.users.messages.modifyorgmail.users.messages.attachments.get, you MUST explicitly define a stub method on theFakeAdvGmailMessagesclass that invokesthis._call(). - Worker Thread Dot-Notation (
sxGmail): The synchronous worker wrapper (sxGmailinsxgmail.js) was updated to support dot notation. When adding deeply nested API calls (e.g.,method: 'attachments.get'),sxGmailcan iteratively resolve the nested function context on thegoogleapisclient. - Gmail Object State Mutation: Modifying labels on a
FakeGmailMessageorFakeGmailThread(e.g.,addLabel(),markRead()) via the REST API does not automatically update the local object's cached labels or headers. To maintain parity with Live GAS ("forces the message to refresh"), modifier methods MUST conclude by calling and returningthis.refresh(), which re-fetches the latest state from the API. - Draft Creation & Payload Hydration: When
Gmail.Users.Drafts.createreturns a draft resource, the embedded.messageobject is a minimal stub containing onlyidandthreadId. It lacks thepayloadand headers. Therefore,FakeGmailDraft.getMessage()MUST perform a distinctGmail.Users.Messages.getAPI call using the message ID to retrieve the fully hydrated message (otherwisegetSubject(),getBody(), etc., will be empty).
Caching & Data Mutation (CRITICAL)
- Problem: When data is returned from a local cache (e.g.,
sheetsCacher), it may be returned as a reference. If the calling code mutates this data (e.g., usingArray.prototype.shift()on results fromgetValues()), the mutation affects the cache itself. Subsequent calls for the same data will then return the mutated (incorrect) results. - Fix: ALWAYS return a deep copy of data from the cache. In
Syncit.js, ensure that bothgetEntryresults and data being passed tosetEntryare deep-copied (e.g., usingJSON.parse(JSON.stringify(data))). This ensures that the cache remains an immutable snapshot of the API response and that each caller receives a fresh, independent copy. - Implementation: The
fxGenericandfxDriveGetfunctions inSyncit.jshave been updated to usenormalizeSerialization()for this purpose.
Iterators and API Object Wrapping (CRITICAL)
- Problem: When fetching a list of resources (like
Drive.Files.list), the API returns plain JSON objects. If you convert an entire chunk of these objects into class instances (e.g.,FakeDriveFolder) prematurely and store them in the state (ortank), and then subsequently pass those instances back through the instantiation function (__settleClass), you will double-wrap them. This causes the internalthis.metato be a Fake instance instead of a plain object. - Consequence: This corruption leaks into the
improveFileCachemechanism (since the cached "raw" data is actually an instance). Later API calls that rely on readingthis.meta(e.g., checkingReflect.has(this.meta, 'id')) fail becausenormalizeSerializationstrips the prototype properties, resulting in a plain object missing its core fields. This leads to infinite resolution loops (e.g.,RangeError: Maximum call stack size exceededingetId()). - Fix: Generators and iterators (like
filesink()indriveiterators.js) MUST store only plain API JSON objects in their state (tank). Only convert the raw API object into a Fake instance at the exact moment it isyielded or returned to the caller.
Google Drive API vs Apps Script Roles (Parity)
- Problem: When fetching the users attached to a file, the live Google Drive API (and thus
gas-fakesusing theDrive.Permissionsendpoint) strictly isolates users by their specific role (e.g.,writer,reader). However, Live Apps Script behaves differently:getViewers()returns anyone with at least view access (including Editors and the Owner), andgetEditors()returns anyone with at least edit access (including the Owner). - Fix: The
getSharers()helper infilesharers.jsdynamically expands the queried roles based on this hierarchy to match live GAS behavior. Specifically:- When querying for
writer, we also fetchowner. - When querying for
readerorcommenter, we fetchwriterandowneras well.
- When querying for
Slides API ColorScheme & Role Hierarchy (CRITICAL)
- Inheritance: In the Google Slides REST API, the
colorSchemeproperty is only present onMasterpages.SlideandLayoutpages inherit their color scheme from their parent master.gas-fakesemulates this by resolving the master page whengetColorScheme()is called on a slide or layout. - Update Constraints: When updating a
ColorSchemevia the API (updatePageProperties), you MUST provide the entire array of 12 theme color pairs (Dark 1, Light 1, etc.). Providing only the updated color will result in an API error. - Data Structure Inconsistency: While the REST API documentation for
OpaqueColorspecifies a nestedrgbColorobject,ColorSchemeresults (and updates) often use a flat structure wherered,green, andblueare direct properties of the color object.gas-fakeshandles both formats to ensure compatibility. - Layout Properties: In the Slides API, a layout's connection to its master is stored in
layoutProperties.masterObjectId, not at the top level of the page resource. - Background Fill propertyState: The Slides REST API returns the
solidFillobject even whenpropertyStateis'NOT_RENDERED'(representing transparent/none). When implementinggetType()orisVisible(), you must verify thatpropertyState !== 'NOT_RENDERED'to correctly identify transparent fills.
Delivery
- Output the complete code for modified or newly created service classes and test scripts.
- ALWAYS output the updated
SKILL.mdwhen new knowledge is extracted and crystallized.
Documentation & Progress Tracking (CRITICAL)
- Do NOT update progress files manually: Files in the
progress/directory (e.g.,progress/spreadsheet.md) and the top-levelprogress.mdare generated automatically. - Generation Pipeline: After implementing or modifying ANY methods, classes, or enums, you MUST run the documentation generation pipeline to ensure your changes are discoverable and accurately reflected in the
progress/documentation. This acts as your "Definition of Done".
(This command executes the full documentation pipeline includingnpm run docsgi-analyzer-all.js,gi-render.js, andgi-progress-summary.js.) - Detection Logic: The analyzer (
doccreation/gi-analyzer-all.js) detects implemented methods by searching for method names in thesrc/directory.- If a method is implemented in a base class or uses a synonym, ensure the class is correctly mapped in the
classSynonymsobject withindoccreation/gi-analyzer-all.js. - For dynamically generated methods (like
require*inDataValidationBuilderorset*/get*inRange), the analyzer must be explicitly updated to map these methods from their source definitions (e.g.,datavalidationcriteriamapping.jsorsheetrangemakers.js) to the target class.
- If a method is implemented in a base class or uses a synonym, ensure the class is correctly mapped in the
- In-Progress Status: Methods that call
notYetImplemented()are automatically marked asin progress. Once the implementation is complete and the call tonotYetImplemented()is removed, the status will switch tocompletedupon running the pipeline.
Chart Generation API Parity (SpreadsheetApp.newChart)
When implementing or modifying EmbeddedChartBuilder features, you must handle the strict differences between Google's Java V8 engine and the actual Sheets REST API payloads:
- Enum Strictness: Live GAS actively rejects string literals for
ChartsEnums (e.g., passing"SHOW_ALL"instead ofCharts.ChartHiddenDimensionStrategy.SHOW_ALLthrowsThe parameters (String) don't match the method signature). All new Enums MUST be mapped insrc/services/enums/and exposed via the parentFakeAppproxy. - REST API Translation: The structure of the
EmbeddedChartBuilderdoes not match the Google Sheets REST API.BOTTOMbecomesBOTTOM_LEGEND.PIEandHISTOGRAMcharts cannot be sent in abasicChartspec wrapper; they require top-levelpieChartandhistogramChartpayloads.COMBOcharts will crash the Sheets API if their internal series arrays are missing explicit type definitions (COLUMNorLINE). The visual default fallback in Apps Script isCOLUMN.- Ensure all Enum and API-specific restructuring occurs in the
.build()translation layer, or within dedicated mappers likechartenummapping.js.
- Dynamic toString: A Live GAS builder's
toString()output changes dynamically depending on the active internal chart type (e.g.,com.google.apps.maestro...vsEmbeddedPieChartBuilder). UseFakeEmbeddedChartBuilder's dynamictoString()pattern to maintain parity. - Method Availability (Live GAS Crash Warning): Live GAS does not support visual formatting methods (
setTitle,setBackgroundColor) on the rootEmbeddedChartBuilder; they are only available after casting (.asPieChart()). Furthermore,setHiddenDimensionStrategywill throw a backendUnexpected errorif called before assigning a type, or if called on an incompatible type (like a Pie chart).
Environment-Agnostic Test Design (CRITICAL)
- No Direct Mock Class References: Test files MUST NOT import or directly reference fake classes using
new(e.g.new FakeElement(),new FakeAttribute(), etc.). These classes do not exist in the live Google Apps Script environment, where the same tests are run. Instead, always instantiate objects via the public factory methods of their respective service (e.g.,XmlService.createElement()) and assert against properties instead of direct object reference comparisons. - Private Data Structures: Under no circumstances should test files directly assert against internal
gas-fakesstructural properties (e.g., checkingbuilder.__apiChart.spec.title). The test suite executes against both local Node.js mocks and Live Apps Script Java classes. Live Apps Script does not expose these internal variables, causing tests to crash. - gas-fakes Specific Objects (
__behavior): Objects likeScriptApp.__behaviororsandboxModeexist ONLY in the local Node.js environment. If you need to manipulate the sandbox during a test (e.g., adding a whitelist ID), you MUST wrap that code in anif (ScriptApp.isFake)block. Attempting to accessScriptApp.__behavior.sandboxModein Live Apps Script will result in aTypeError: Cannot read properties of undefined. - Test Outcomes: Only assert against public, documented getter/setter behavior or the visual/functional output of a method (e.g., inserting the chart into a sheet and validating the resulting API object). Avoid bypassing validations using
ScriptApp.isFakefor private implementation assertions unless strictly manipulating the local test harness (like the sandbox).
Exporting Local Variables for Templates & RPC (Parity)
- Problem: When developing an Apps Script project locally with
gas-fakes, templates (<?!= Include.html() ?>) and client-side RPC calls (google.script.run.foo()) require backend functions/variables to be explicitly exported from the entry point (index.js). - Constraint: The Google Apps Script V8 engine DOES NOT support ES6
exportorimportstatements. Including them will cause syntax errors in the Apps Script environment. - Fix (Using togas): Use the
gas-fakes togasCLI command to prepare your local code for deployment.- The
togascommand automatically comments outimportstatements and removesexportkeywords. - It copies the transformed files to a target directory (configured via
initor--target). - It uses
clasp pushto deploy the transformed code to Apps Script.
- The
- Result: You can maintain idiomatic Node.js code with ESM imports/exports locally while ensuring the deployed Apps Script code remains valid.
Local Documentation Discovery (Parity & Method Verification)
For rapid and accurate verification of Apps Script class and method signatures, parameter lists, return types, and descriptions, developers should prioritize searching the local documentation repository.
The file /Users/brucemcpherson/Documents/repos/gas-fakes/doccreation/gi-fake-all.json contains a complete, comprehensive duplicate of all Apps Script documentation.
Prioritization Strategy:
Instead of relying on external web searches, which can be slow, prone to outdated information, or lack precise syntax matching, use local command-line tools (grep, jq, etc.) to query gi-fake-all.json.
Why Local Search is Superior:
- Efficiency: Local searches are instantaneous compared to network latency.
- Offline Access: Documentation is available even without an internet connection.
- Guaranteed Accuracy: The JSON file provides a guaranteed, static snapshot of the documentation, ensuring that the syntax and usage details match the expected environment, eliminating ambiguity found in general web searches.