NotionRubyMapping に Create a page の position object を追加(1) : hkob の雑記録 (388)

はじめに

hkob の雑記録の第388回目(通算785日目)は、NotionRubyMapping に position object を追加します。今月、Create a page の際に position object を指定できるようになりました。詳しくは1月21日の記事で解説しています。今日は、この実装をするためのテストデータを作成します。

Create a Page の position object : hkob の雑記録 (386) - hkob’s blog

テストページの作成

まず、テスト用のページを作成します。ページの中身は何もないところから始めます。

空ページの作成

page_end への追加

まず、page_end への追加を行います。スクリプトは以下のようになります。ページ内へのページ追加となるので、title プロパティしかありません。この場合の識別子は title となります。このことを Notion API 活用術に書いてなかった気がします。追加しておきましょう。position object を省略した時は page_end になるので、わざわざ記述する必要はないのですが、フレームワークとしては対応する必要があるでしょう。 create_page_page_end.sh は以下のようになります。

curl 'https://api.notion.com/v1/pages' \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2025-09-03" \
  --data '{
    "parent": {
      "type": "page_id",
      "page_id": "2f0d8e4e98ab8065b3a2ec9fd4b3e57a"
    },
    "properties": {
      "title": {
        "type": "title",
        "title": [
          {
            "type": "text",
            "text": {
              "content": "New Page at page_end",
              "link": null
            },
            "plain_text": "New Page at page_end",
            "href": null
          }
        ]
      }
    },
    "position": {
      "type": "page_end"
    }
  }'

実行するとページ下部にページが作成されました。

page_end への追加

page_start への追加

これまでできなかったページトップへの追加です。当然 page_start に変更するだけです。

curl 'https://api.notion.com/v1/pages' \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2025-09-03" \
  --data '{
    "parent": {
      "type": "page_id",
      "page_id": "2f0d8e4e98ab8065b3a2ec9fd4b3e57a"
    },
    "properties": {
      "title": {
        "type": "title",
        "title": [
          {
            "type": "text",
            "text": {
              "content": "New Page at page_start",
              "link": null
            },
            "plain_text": "New Page at page_start",
            "href": null
          }
        ]
      }
    },
    "position": {
      "type": "page_start"
    }
  }'

問題なくページのトップに作成されました。

page_start への追加

after_block への追加

page_start で作成したページの id を使って、after_block のテストを作成します。

curl 'https://api.notion.com/v1/pages' \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2025-09-03" \
  --data '{
    "parent": {
      "type": "page_id",
      "page_id": "2f0d8e4e98ab8065b3a2ec9fd4b3e57a"
    },
    "properties": {
      "title": {
        "type": "title",
        "title": [
          {
            "type": "text",
            "text": {
              "content": "New Page at after_block",
              "link": null
            },
            "plain_text": "New Page at after_block",
            "href": null
          }
        ]
      }
    },
    "position": {
      "type": "after_block",
      "after_block": {
        "id": "2f0d8e4e-98ab-812c-a8f5-cce62b2d3f6e"
      }
    }
  }'

実行すると page_start と page_end の中間にページが作成されました。

after_block への追加

テストの作成

テストデータを作成しただけで終わってしまうと短すぎるので、テストまで記載してしまいましょう。まず、親ページの PAGE_ID を定義しておきます。

    describe "position object for create a page" do
      let(:ppid) { TestConnection::POSITION_TEST_PARENT_PAGE_ID }
      let(:parent_page) { Page.new id: ppid }

      [
        ["page_end", "page_end", {"type" => "page_end"}, TestConnection::POSITION_TEST_PAGE_END_ID],
        ["page_start", "page_start", {"type" => "page_start"}, TestConnection::POSITION_TEST_PAGE_START_ID],
        ["after_block", TestConnection::POSITION_TEST_PAGE_START_ID,
         {"type" => "after_block", "after_block" => {"id" => TestConnection::POSITION_TEST_PAGE_START_ID}},
         TestConnection::POSITION_TEST_AFTER_BLOCK_ID],
      ].each do |(key, value, position, id)|
        context "when it creates at #{key}" do
          let(:title) { "New Page at #{key}" }

          context "when not dry_run" do
            let(:target) do
              parent_page.create_child_page position: value do |_, pp|
                pp["title"] << title
              end
            end

            it { expect(target.id).to eq id }
            it { expect(nc.hex_id(target.parent_id)).to eq ppid }
          end

          context "when dry_run" do
            let(:dry_run) do
              parent_page.create_child_page position: value, dry_run: true do |_, pp|
                pp["title"] << title
              end
            end

            it_behaves_like "dry run", :post, :pages_path, json: {
              "properties" => {
                "title" => {
                  "type" => "title",
                  "title" => [
                    {
                      "type" => "text",
                      "text" => {
                        "content" => "New Page at #{key}",
                        "link" => nil,
                      },
                      "plain_text" => "New Page at #{key}",
                      "href" => nil,
                    },
                  ],
                },
              },
              "parent" => {
                "type" => "page_id",
                "page_id" => TestConnection::POSITION_TEST_PARENT_PAGE_ID,
              },
              "position" => position,
            }
          end
        end
      end
    end

3つのケースに対してはテスト部分は共通なので、変化分のみをパラメータとして括り出し、3回テストを実行するようにしています。それぞれ実際に WebMock を使った場合と dry_run のスクリプト出力結果をテストしています。

テスト結果

テストを実行したところ、create_child_page が実装されていないということに、今気づきました。データソース内にページを作成する実装はしていたものの、ページ内にページを追加するメソッドを忘れていたようです。これを忘れていたから、Notion API 活用術でも title の表記を忘れていたのですね。Page の下に Page を作成する場合は、Title property しか存在せず title 以外の文字列は設定できないので、自動的に用意されることにします。上のテストではそれを踏まえて TitleProperty の作成部分を消してしまいました。

     NoMethodError:
       undefined method 'create_child_page' for an instance of NotionRubyMapping::Page
     Shared Example Group: "dry run" called from ./spec/notion_ruby_mapping/blocks/page_spec.rb:1206                                                                        
     # ./spec/notion_ruby_mapping/blocks/page_spec.rb:1201:in 'block (6 levels) in <module:NotionRubyMapping>'                                                              
     # ./spec/spec_helper.rb:3020:in 'block (2 levels) in <module:RSpec>'

Finished in 1.09 seconds (files took 1.02 seconds to load)
3012 examples, 9 failures

おわりに

これまで Page 内に Page を作成することをしていなかったので、実装漏れに全く気づいていませんでした。明日は Notion 座談会なので、土曜日に実装することにします。だいぶアップデートもたまったので、今回の実装が完了したらバージョンアップをリリースすることにしましょう。

hkob.notion.site