Skip to content

Remaining Endpoint Coverage ​

Needs an access token

Tests the 16 endpoints not covered by other examples:

  • 10 fleet write operations
  • 3 asset POST endpoints
  • 1 calendar PUT (respond to event)
  • 1 CSPA charge cost POST
  • 1 dogma dynamic item GET

REQUIRES AUTHENTICATION and being in-game in a fleet as fleet commander.

Calls: dogma.getDynamicItemInfo · characters.postCspaChargeCost · assets.getCharacterAssets · assets.postCharacterAssetLocations · assets.postCorporationAssetLocations · assets.postCorporationAssetNames · fleets.getCharacterFleetInfo · fleets.updateFleet · fleets.createFleetWing · fleets.createFleetSquad · fleets.deleteFleetSquad · fleets.deleteFleetWing · fleets.getFleetWings · fleets.createFleetInvitation

Run it ​

bash
git clone https://github.com/lgriffin/ESI.ts.git && cd ESI.ts
npm ci
npm run example:remaining-coverage

examples/remaining-coverage.ts on GitHub. The imports below are written as a consumer of the package writes them; the file in the repository imports from ../src.

Source ​

ts
import { EsiClient } from '@lgriffin/esi.ts';
import { EsiError } from '@lgriffin/esi.ts/errors';
import { createConsoleLogger } from '@lgriffin/esi.ts';

// The program's own output. The client logs through the same console sink
// at ESI_LOG_LEVEL (default warn), so its diagnostics stay out of the way.
const log = createConsoleLogger('info');
const esiLog = createConsoleLogger();

const CHARACTER_ID = 90439768;
const CORP_ID = 98135622;

async function tryEndpoint(
  label: string,
  fn: () => Promise<unknown>,
): Promise<{ label: string; status: string; detail: string }> {
  try {
    const result = await fn();
    const detail =
      result === undefined || result === null
        ? 'OK (no content)'
        : typeof result === 'object'
          ? JSON.stringify(result).slice(0, 120)
          : String(result);
    return { label, status: 'PASS', detail };
  } catch (err) {
    if (err instanceof EsiError) {
      return {
        label,
        status:
          err.statusCode === 404 ? 'PASS (404)' : `FAIL (${err.statusCode})`,
        detail: err.message.slice(0, 100),
      };
    }
    return {
      label,
      status: 'FAIL',
      detail: err instanceof Error ? err.message.slice(0, 100) : String(err),
    };
  }
}

async function main() {
  const client = new EsiClient({ logger: esiLog });
  const results: { label: string; status: string; detail: string }[] = [];

  log.info('Remaining Endpoint Coverage Test\n');
  log.info('='.repeat(60));

  // --- 1. Dogma Dynamic Item (public, no auth) ---
  log.info('\n1. Dogma Dynamic Item');
  log.info('-'.repeat(40));
  results.push(
    await tryEndpoint('GET dogma/dynamic/items/{typeId}/{itemId}', async () => {
      return await client.dogma.getDynamicItemInfo(47789, 1049829575325);
    }),
  );

  // --- 2. CSPA Charge Cost ---
  log.info('\n2. CSPA Charge Cost');
  log.info('-'.repeat(40));
  results.push(
    await tryEndpoint('POST characters/{id}/cspa/', async () => {
      return await client.characters.postCspaChargeCost(
        CHARACTER_ID,
        [90404873],
      );
    }),
  );

  // --- 3. Asset Location & Name POSTs ---
  log.info('\n3. Asset POST Endpoints');
  log.info('-'.repeat(40));

  // Get an asset item ID first
  let assetItemId: number | undefined;
  try {
    const assets = await client.assets.getCharacterAssets(CHARACTER_ID);
    if (assets.length > 0) {
      assetItemId = assets[0]!.item_id;
    }
  } catch {
    // ignore
  }

  if (assetItemId) {
    results.push(
      await tryEndpoint('POST characters/{id}/assets/locations/', async () => {
        return await client.assets.postCharacterAssetLocations(CHARACTER_ID, [
          assetItemId!,
        ]);
      }),
    );
  } else {
    results.push({
      label: 'POST characters/{id}/assets/locations/',
      status: 'SKIP',
      detail: 'No assets found',
    });
  }

  results.push(
    await tryEndpoint('POST corporations/{id}/assets/locations/', async () => {
      return await client.assets.postCorporationAssetLocations(CORP_ID, [1]);
    }),
  );

  results.push(
    await tryEndpoint('POST corporations/{id}/assets/names/', async () => {
      return await client.assets.postCorporationAssetNames(CORP_ID, [1]);
    }),
  );

  // --- 4. Calendar: Respond to Event ---
  log.info('\n4. Calendar Respond');
  log.info('-'.repeat(40));
  // Event 3267240 exists from earlier calendar-search run
  results.push(
    await tryEndpoint('PUT characters/{id}/calendar/{eventId}/', async () => {
      return await client.calendar.respondToCalendarEvent(
        CHARACTER_ID,
        3267240,
        'accepted',
      );
    }),
  );

  // --- 5. Fleet Write Operations ---
  log.info('\n5. Fleet Write Operations');
  log.info('-'.repeat(40));

  let fleetId: number | undefined;
  let wingId: number | undefined;
  let squadId: number | undefined;

  // Get fleet info
  try {
    const fleetInfo = await client.fleets.getCharacterFleetInfo(CHARACTER_ID);
    fleetId = fleetInfo.fleet_id;
    log.info(`  Fleet ID: ${fleetId}`);
  } catch (err) {
    log.info('  Not in a fleet — skipping fleet write tests');
  }

  if (fleetId) {
    // 5a. Update fleet MOTD
    results.push(
      await tryEndpoint('PUT fleets/{fleetId} (updateFleet)', async () => {
        return await client.fleets.updateFleet(fleetId!, {
          motd: 'ESI.ts coverage test',
          is_free_move: false,
        });
      }),
    );

    // 5b. Create a wing
    let newWingId: number | undefined;
    results.push(
      await tryEndpoint(
        'POST fleets/{fleetId}/wings/ (createFleetWing)',
        async () => {
          const result = await client.fleets.createFleetWing(fleetId!, {});
          newWingId = result.wing_id;
          return result;
        },
      ),
    );

    if (newWingId) {
      wingId = newWingId;

      // 5c. Rename wing
      results.push(
        await tryEndpoint(
          'PUT fleets/{fleetId}/wings/{wingId}/ (renameFleetWing)',
          async () => {
            return await client.fleets.renameFleetWing(
              fleetId!,
              wingId!,
              'Test Wing',
            );
          },
        ),
      );

      // 5d. Create a squad in the new wing
      let newSquadId: number | undefined;
      results.push(
        await tryEndpoint(
          'POST fleets/{fleetId}/wings/{wingId}/squads/ (createFleetSquad)',
          async () => {
            const result = await client.fleets.createFleetSquad(
              fleetId!,
              wingId!,
            );
            newSquadId = result.squad_id;
            return result;
          },
        ),
      );

      if (newSquadId) {
        squadId = newSquadId;

        // 5e. Rename squad
        results.push(
          await tryEndpoint(
            'PUT fleets/{fleetId}/squads/{squadId}/ (renameFleetSquad)',
            async () => {
              return await client.fleets.renameFleetSquad(
                fleetId!,
                squadId!,
                'Test Squad',
              );
            },
          ),
        );

        // 5f. Delete squad
        results.push(
          await tryEndpoint(
            'DELETE fleets/{fleetId}/squads/{squadId}/ (deleteFleetSquad)',
            async () => {
              return await client.fleets.deleteFleetSquad(fleetId!, squadId!);
            },
          ),
        );
      }

      // 5g. Delete wing
      results.push(
        await tryEndpoint(
          'DELETE fleets/{fleetId}/wings/{wingId}/ (deleteFleetWing)',
          async () => {
            return await client.fleets.deleteFleetWing(fleetId!, wingId!);
          },
        ),
      );
    }

    // 5h. Move fleet member (move self to a different squad — may 404)
    const wings = await client.fleets.getFleetWings(fleetId);
    const existingSquad = wings[0]?.squads?.[0];
    if (existingSquad) {
      results.push(
        await tryEndpoint(
          'PUT fleets/{fleetId}/members/{memberId}/ (moveFleetMember)',
          async () => {
            return await client.fleets.moveFleetMember(fleetId!, CHARACTER_ID, {
              role: 'squad_commander',
              wing_id: wings[0]!.id,
              squad_id: existingSquad.id,
            });
          },
        ),
      );

      // Move back to fleet commander
      await client.fleets
        .moveFleetMember(fleetId, CHARACTER_ID, {
          role: 'fleet_commander',
          wing_id: -1,
          squad_id: -1,
        })
        .catch(() => {});
    }

    // 5i. Create fleet invitation (invite a character — will fail if not online, that's OK)
    results.push(
      await tryEndpoint(
        'POST fleets/{fleetId}/members/ (createFleetInvitation)',
        async () => {
          return await client.fleets.createFleetInvitation(fleetId!, {
            character_id: 90404873,
            role: 'squad_member',
          });
        },
      ),
    );

    // 5j. Kick fleet member (kick the invite target if they joined, otherwise expect 404)
    results.push(
      await tryEndpoint(
        'DELETE fleets/{fleetId}/members/{memberId}/ (kickFleetMember)',
        async () => {
          return await client.fleets.kickFleetMember(fleetId!, 90404873);
        },
      ),
    );

    // Restore MOTD
    await client.fleets
      .updateFleet(fleetId, { motd: '', is_free_move: false })
      .catch(() => {});
  }

  // --- Summary ---
  log.info('\n' + '='.repeat(60));
  log.info('RESULTS\n');
  const maxLabel = Math.max(...results.map((r) => r.label.length));
  for (const r of results) {
    const pad = r.label.padEnd(maxLabel + 2);
    log.info(`  ${pad} ${r.status.padEnd(12)} ${r.detail}`);
  }

  const passed = results.filter((r) => r.status.startsWith('PASS')).length;
  const failed = results.filter((r) => r.status.startsWith('FAIL')).length;
  const skipped = results.filter((r) => r.status === 'SKIP').length;
  log.info(
    `\n${passed} passed, ${failed} failed, ${skipped} skipped out of ${results.length} endpoints`,
  );

  await client.shutdown();
}

main();

Released under the GPL-3.0-or-later license.